slog.Handler.Handle()

September 2, 2026

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.
	// Canceling the context should not affect record processing.
	// (Among other things, log messages may be necessary to debug a
	// cancellation-related problem.)
	//
	// Handle methods that produce output should observe the following rules:
	//   - If r.Time is the zero time, ignore the time.
	//   - If r.PC is zero, ignore it.
	//   - Attr's values should be resolved.
	//   - If an Attr's key and value are both the zero value, ignore the Attr.
	//     This can be tested with attr.Equal(Attr{}).
	//   - If a group's key is empty, inline the group's Attrs.
	//   - If a group has no Attrs (even if it has a non-empty key),
	//     ignore it.
	//
	// [Logger] discards any errors from Handle. Wrap the Handle method to
	// process any errors from Handlers.
	Handle(context.Context, Record) error

When implementing a handler, the docs above explain two general rules that must be followed:

- Don't log if the record's level is lower than the handler's configured level.
- Ignore certain zero values.

but what I find most interesting is that `Handle` returns an eror that is explicitly ignored.  I don't know the reason this choice was made. It strikes me as an unusual departure from convention. And the sugested work-around I find also to be odd:  Wrap the `Handle` method to handle any errors.  This puts the responsibility for error handling in an awkward spot—neither the `Handler` author, nor the `logger` consumer are directly responsible. Rather, a `Handler` needs to be wrapped with custom error-handling code.

My personal advice: If you're writing a log handler, don't return errors from `Handle`. 😊 If you do return an error there, I'd be careful to document that clearly in your package's documention.

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.


Anatomy of a log/slog logger

Unlike the older log package, which provides a single *log.Logger type as its primary interface, log/slog has a two-tiered architecture. This is roughly the same architecture used by the database/sql package: One interface implements a handler (or “driver” for database/sql), and another interface is consumed. The package itself provides the intermediate translation. This is essentially a localized example of ports-and-adaptors or hexagonal architecture. Here’s how the GoDoc for the package explains it:


Attribute equality

func (Attr) Equal func (a Attr) Equal(b Attr) bool Equal reports whether a and b have equal keys and values. That’s a pretty obvious, and opaque statement. How is equality determined? We have to look at the source to determine: func (a Attr) Equal(b Attr) bool { return a.Key == b.Key && a.Value.Equal(b.Value) } Okay, so it returns true if the keys are equal (that’s simple—they’re just strings) AND if the values are equal.

Get daily content like this in your inbox!

Subscribe