Contexts

May 4, 2026

[**Idiomatic Testing in Go**](/idiomatic-testing/) starts TOMORROW!

My my, how time flies! There are still a few seats available, and there’s still time to sign up.

Learn how to get the most out of the tests in your Go app!

One feature I often see overlooked capability of the log/slog package, is to extract log key/value pairs from context:

Contexts

Some handlers may wish to include information from the context.Context that is available at the call site. One example of such information is the identifier for the current span when tracing is enabled.

The Logger.Log and Logger.LogAttrs methods take a context as a first argument, as do their corresponding top-level functions.

Although the convenience methods on Logger (Info and so on) and the corresponding top-level functions do not take a context, the alternatives ending in “Context” do. For example,

slog.InfoContext(ctx, "message")

It is recommended to pass a context to an output method if one is available.

Why is this frequently overlooked?

Well, one reason is that the handlers bundled in the standard library do not, by default, extract any key/value pairs from the context!

So while the official recommendation is to pass context, when available, unless you’re using a third-party logging handler, you’re passing the context to a black hole.

Is it still good advice to pass context? Yes, it probably is. When you’re writing new code,the cost of passing context is negligible. But at some possible future date, when you add a custom or third-party log handler that requires context, retrofitting your entire application can be quite painful! (Ask me how I know….)


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


slog Handler methods

slog.Handler is an interface type. We’re going to look at each method on that interface in turn. Understanding these methods is valuable if you’re ever implementing your own handler. If you’re only using slog to produce logs using existing handlers, you could skip this part… though maybe you’ll learn something interesting anyway! type Handler type Handler interface { // Enabled reports whether the handler handles records at the given level. // The handler ignores records whose level is lower.


When not to use context values

Storing values in a context is quite flexible, but comes without strict type safety, and obscures the API. So what can we do about this? First, for type safety, we’re limited to runtime assertions: userID := ctx.Value(userIDKey).(string) But this can panic if we ever get an unexpected value (or even nil). So to make it safer, we can use the two-variable assignment form, which yields a bool indicating success: userID, ok := ctx.


slog.HandlerOptions

Now we’ll begin looking at HandlerOptions. Despite the Handler-centricity, this is something we care heavily about as mere users of the slog library. Whenever you instantiate either slog.JSONHandler or slog.TextHandler, you have the option of providing a HandlerOptions object, to tweak the default handler behavior. We’ll look at each of the config options, one at a time. type HandlerOptions type HandlerOptions struct { // AddSource causes the handler to compute the source code position // of the log statement and add a SourceKey attribute to the output.

Get daily content like this in your inbox!

Subscribe