Logging common fields

April 16, 2026

It’s common that you’ll want to include certain attributes in all logs in an application or component. log/slog makes this pretty easy.

Overview

Some attributes are common to many log calls. For example, you may wish to include the URL or trace identifier of a server request with all log events arising from the request. Rather than repeat the attribute with every log call, you can use Logger.With to construct a new Logger containing the attributes:

logger2 := logger.With("url", r.URL)

The arguments to With are the same key-value pairs used in Logger.Info. The result is a new Logger with the same handler as the original, but additional attributes that will appear in the output of every call.

Put another way:

logger.Error("oh noes!", "foo", "bar")

and

logger = logger.With("foo", "bar")
logger.Error("oh noes!")

produce the same log output. The difference is, that in the second form, you can re-use the same logger for many logs, without repeating the common attribute:

func run(logger *slog.Logger) {
  logger = logger.With("key", "value")
  doFoo(logger)
  doBar(logger)
}

func doFoo(logger *slog.Logger) {
  /* ... */
  logger.Info("Did foo")
}

func doBar(logger *slog.Logger) {
  /* ... */
  logger.Info("Did bar")
}

This will log:

time=... level=INFO msg="Did foo" key=value
time=... level=INFO msg="Did bar" key=value

Share this

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

Unsure? Browse the archive .

Related Content


Performance considerations

You’ve likely wondered why the log/slog package has some odd-looking functions and concepts in some places. Why do you set a handler’s level to a Leveler value, rather than a simple Level? Why so many ways to create key/value pairs ("key", "value" vs "key", slog.AnyValue("value") vs "key", slog.StringValue("value") vs slog.Any("key", "value") vs slog.String("key", "value"))? It mostly comes down to one thing: Performance. Or, more accurately, trying to balance performance with an easy-to-use API.


slog.Handler

I’m probably doing this in backwards order, but that’s the order the GoDoc presents it… Now that we’ve looked at each of the methods of the Handler interface, we come to its general description: type Handler A Handler handles log records produced by a Logger. A typical handler may print log records to standard error, or write them to a file or database, or perhaps augment them with additional attributes and pass them on to another handler.


slog.Handler.WithGroup

I hope everyone had a good Labor Day weekend… even if you’re not in the US and had to/got to labor on Monday. Speaking of labor, I’m looking for new clients! If you could use some world class Go expertise on your project, please reach out! type Handler type Handler interface { … // WithGroup returns a new Handler with the given group appended to // the receiver's existing groups. // The keys of all subsequent attributes, whether added by With or in a // Record, should be qualified by the sequence of group names.

Get daily content like this in your inbox!

Subscribe