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


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.


Values

TIL Logger.LogAttrs is a thing! But what is that thing?? Yesterday I mentioned that using an slog.Attr can be marginally more efficient than using naked key/value pairs in a log call. While true, that glosses over what is likely to be a much more impactful performance consideration in certain applications… Attrs and Values … The value part of an Attr is a type called Value. Like an [any], a Value can hold any Go value, but it can represent typical values, including all numbers and strings, without an allocation.


Attrs

We’ve been talking about key/value pairs. The log/slog package has a name for these: Attr (short for “attribute”). And there’s more than one way to build an attribute: Attrs and Values An Attr is a key-value pair. The Logger output methods accept Attrs as well as alternating keys and values. The statement slog.Info("hello", slog.Int("count", 3)) behaves the same as slog.Info("hello", "count", 3) There are convenience constructors for Attr such as Int, String, and Bool for common types, as well as the function Any for constructing Attrs of any type.

Get daily content like this in your inbox!

Subscribe