Documentation ¶
Overview ¶
Package protoslog provides utilities for using protocol buffer messages with the log/slog package.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Message ¶
Message returns a slog.Attr for a proto.Message using the provided options. Note that these options are ignored if the slog.Value is handled by a Handler.
Example ¶
updated := time.Date(2012, time.September, 2, 15, 53, 0, 0, time.UTC) msg := &pb.User{ Id: 123, Name: "foobar", Email: "foo@bar.com", // debug_redact Location: &pb.Location{ Latitude: 1.23, Longitude: 4.56, }, Hobbies: []string{"track", "field"}, Pets: map[string]pb.PetType{ "Rover": pb.PetType_PET_TYPE_DOG, "Fifi": pb.PetType_PET_TYPE_CAT, }, Updated: timestamppb.New(updated), Best_100MTime: durationpb.New(9*time.Second + 580*time.Millisecond), } logger := slog.New(slogHandler()) logger.Info("some event", protoslog.Message("user", msg))
Output: level=INFO msg="some event" user.id=123 user.name=foobar user.email=REDACTED user.location.latitude=1.23 user.location.longitude=4.56 user.hobbies.0=track user.hobbies.1=field user.pets.Fifi=PET_TYPE_CAT user.pets.Rover=PET_TYPE_DOG user.updated=2012-09-02T15:53:00.000Z user.best_100m_time=9.58s
func MessageValue ¶
MessageValue returns a slog.Value for a proto.Message using the provided options. Note that these options are ignored if the slog.Value is handled by a Handler.
Types ¶
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler is a slog.Handler that properly converts proto.Message attributes into the appropriate slog.Value, before delegating to a child slog.Handler. The Handler's options merge with the options associated with proto.Message types that implement slog.LogValuer. Handler must be constructed via NewHandler.
Example ¶
msg := &pb.User{ Id: 123, Best_100MTime: durationpb.New(9*time.Second + 580*time.Millisecond), } handler := protoslog.NewHandler(slogHandler()) logger := slog.New(handler) logger.Info("hello world", "user", msg)
Output: level=INFO msg="hello world" user.id=123 user.best_100m_time=9.58s
Example (AllFields) ¶
msg := &pb.Location{ Latitude: 1.23, } childHandler := slogHandler() logger := slog.New(protoslog.NewHandler(childHandler)) logger.Info("default", "loc", msg) logger = slog.New(protoslog.NewHandler(childHandler, protoslog.WithAllFields())) logger.Info("all", "loc", msg)
Output: level=INFO msg=default loc.latitude=1.23 level=INFO msg=all loc.latitude=1.23 loc.longitude=0
Example (Any) ¶
msg, _ := anypb.New(&pb.Location{ Latitude: 1.23, Longitude: 4.56, }) childHandler := slogHandler() logger := slog.New(protoslog.NewHandler(childHandler)) logger.Info("default", "any", msg) logger.Info("unknown", "any", &anypb.Any{TypeUrl: "foobar"}) logger = slog.New(protoslog.NewHandler(childHandler, protoslog.WithSkipAnys())) logger.Info("skip", "any", msg)
Output: level=INFO msg=default any.@type=type.googleapis.com/Location any.latitude=1.23 any.longitude=4.56 level=INFO msg=unknown any.@type=foobar level=INFO msg=skip any.@type=type.googleapis.com/Location
Example (Redaction) ¶
Messages may contain personal identifiable information (PII), secrets, or similar data that should not be written into a log. Message fields can be annotated with the debug_redact option to identify such values. By default, protoslog will redact these fields, with the behavior customizable via [options].
// message User { fixed64 id = 1; string email = 2 [debug_redact=true]; } msg := &pb.User{ Id: 123, Email: "personal@identifiable.info", } childHandler := slogHandler() logger := slog.New(protoslog.NewHandler(childHandler)) logger.Info("default", "user", msg) logger = slog.New(protoslog.NewHandler(childHandler, protoslog.WithDisableRedactions())) logger.Info("disabled", "user", msg) logger = slog.New(protoslog.NewHandler(childHandler, protoslog.WithElideRedactions())) logger.Info("elided", "user", msg)
Output: level=INFO msg=default user.id=123 user.email=REDACTED level=INFO msg=disabled user.id=123 user.email=personal@identifiable.info level=INFO msg=elided user.id=123
func NewHandler ¶
NewHandler creates a Handler that delegates to child, using the given options. Note that these options merge with any options used in Message, MessageValue, or MessageValuer.
func (Handler) Handle ¶
Handle converts the proto.Message attributes on record before delegating the record to its child handler.
func (Handler) WithAttrs ¶
WithAttrs converts the proto.Message attributes before delegating them to its child handler.
Example ¶
loc := &pb.Location{Latitude: 1.23} msg := &pb.User{Id: 456} logger := slog.New(protoslog.NewHandler(slogHandler())) logger.With("loc", loc).Info("attrs", "user", msg)
Output: level=INFO msg=attrs loc.latitude=1.23 user.id=456
type Option ¶
type Option func(o *options)
Option functions customize generation of a slog.Value from a proto.Message beyond the default behavior.
func WithAllFields ¶
func WithAllFields() Option
WithAllFields indicates that all fields, including unpopulated ones, should be included in slog.Value. Unpopulated members of a oneof are still excluded from the output.
func WithAnyResolver ¶
func WithAnyResolver(resolver protoregistry.MessageTypeResolver) Option
WithAnyResolver is the protoregistry.MessageTypeResolver used to resolve the google.protobuf.Any well-known type into a valid slog.Value. When nil, protoregistry.GlobalTypes is used. If the type cannot be found in the resolver or if unmarshaling fails, only a "@type" field is emitted.
func WithDisableRedactions ¶
func WithDisableRedactions() Option
WithDisableRedactions indicates that fields annotated with the debug_redact option should not be redacted from the slog.Value.
func WithElideRedactions ¶
func WithElideRedactions() Option
WithElideRedactions indicates that redacted fields should be removed from the slog.Value instead of being replaced with REDACTED. WithElideRedactions supersedes WithAllFields.
func WithSkipAnys ¶
func WithSkipAnys() Option
WithSkipAnys indicates that google.protobuf.Any fields should not be unmarshalled during construction of the slog.Value, emitting only a "@type" field.
type Valuer ¶
type Valuer struct { // Message is the proto.Message to produce the slog.Value. Message proto.Message // contains filtered or unexported fields }
Valuer implements slog.LogValuer for a proto.Message to defer computing a slog.Value until it's needed.
func MessageValuer ¶
MessageValuer returns a Valuer for a proto.Message using the provided options. Note that these options are ignored if the Valuer is handled by a Handler.