logctx
Package logctx provides a way to decorate structured log entries with metadata
added to a context.Context
.
Currently, this works with Zap only. But it would be trivial to support other structured logging libraries.
WithMeta creates a new context which contains a hash table of arbitrary metadata strings which can later be easily added to a structured log entry.
For example, if you want to decorate a call tree with some data:
func DoBusinessLogic(ctx context.Context, userID string) error {
ctx = logctx.WithMeta(ctx, logctx.Meta{"user_id": userID})
GetResource(ctx, ...)
}
You can wrap contexts with this helper as much as you want:
func DoBusinessLogic(ctx context.Context, userID string) error {
ctx = logctx.WithMeta(ctx, logctx.Meta{"user_id": userID})
GetResource(ctx, ...)
}
func GetResource(ctx context.Context, ...) {
ctx = logctx.WithMeta(ctx, logctx.Meta{"something_else": xyz})
CallAnotherThing(ctx, ...)
}
Then, when you need to log it out, use logctx.Zap
.
Zap will wrap your Zap log fields with any available metadata from the given
context. Any context returned from calls to WithMeta
will work in this
function and provide a “context” field to the log entry. If the given context
was not decorated with WithMeta
then this function does nothing and just
passes your fields unmodified.
It’s best used directly in a zap log call, with the spread operator:
func (s *service) DoBusinessLogic(ctx context.Context, userID string) error {
s.l.Info("i am doing the thing", logctx.Zap(
zap.String("event_specific", "information"),
)...)
}
In this example, assuming a function higher up in the call chain used the
WithMeta
to add a user_id
, the log entry for this will be:
{
"level": "info",
"msg": "i am doing the thing",
"context": {
"user_id": "the_user_id"
}
}