slog.Handler.WithGroup

September 8, 2026

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.
	//
	// How this qualification happens is up to the Handler, so long as
	// this Handler's attribute keys differ from those of another Handler
	// with a different sequence of group names.
	//
	// A Handler should treat WithGroup as starting a Group of Attrs that ends
	// at the end of the log event. That is,
	//
	//     logger.WithGroup("s").LogAttrs(ctx, level, msg, slog.Int("a", 1), slog.Int("b", 2))
	//
	// should behave like
	//
	//     logger.LogAttrs(ctx, level, msg, slog.Group("s", slog.Int("a", 1), slog.Int("b", 2)))
	//
	// If the name is empty, WithGroup returns the receiver.
	WithGroup(name string) Handler
}

WithGroup serves the same purpose as WithAttrs, but for groups, which we’ve already discussed from the perspective of logging.

The interesting thing to note here is that WithGroup returns a Handler for which all new Attrs are added to the group. In other words, once WithGroup is called on the Handler, there’s no way to “escape” that group. That might sound limiting, but it’s actually quite powerful for a particular case. It’s this behavior that allows you to define a logger that includes all downstream logs in a group. Useful for component-level grouping.

For a contrived example:

logger := /* default logger */
checkoutLogger := logger.WithGroup("checkout")
processCheckout(checkoutLogger, order)
shippingLogger := logger.WithGroup("shipping")
shipProducts(shippingLogger, order)

In this way, any log calls by processCheckout have their attributes added to the “checkout” group, and any by shipProducts have their attributes added to the “shipping” group.


Share this

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

Unsure? Browse the archive .

Related Content


slog.Handler.WithAttrs

type Handler type Handler interface { … // WithAttrs returns a new Handler whose attributes consist of // both the receiver's attributes and the arguments. // The Handler owns the slice: it may retain, modify or discard it. WithAttrs(attrs []Attr) Handler This is likely the most interesting and subtle method of the slog.Handler interface. The important thing to note is that the handler is not mutated in place. Rather, a new handler is meant to be returned.


slog.Handler.Handle()

I had not intended to take a month off, but then GopherCon came, and life happened… but now I’m back, and ready to rock and roll again… Today we’re to the core of the Handler interface: the Handle method. type Handler type Handler interface { … // Handle handles the Record. // It will only be called when Enabled returns true. // The Context argument is as for Enabled. // It is present solely to provide Handlers access to the context's values.


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.

Get daily content like this in your inbox!

Subscribe