slog.Handler

September 9, 2026

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.

Any of the Handler’s methods may be called concurrently with itself or with other methods. It is the responsibility of the Handler to manage this concurrency.

Users of the slog package should not invoke Handler methods directly. They should use the methods of Logger instead.

Before implementing your own handler, consult https://go.dev/s/slog-handler-guide.

Three important things to take away from this:

  1. The handler must handle any concurrency issues, such that it’s safe to call any methods concurrently.
  2. Don’t call handler methods directly, as a user of the slog package.
  3. RTFM 😂 If you’re going to implement a handler, don’t rely merely on this documentation. Read the handler guide.

I don’t plan to disect the handler guide here. That’s a pretty niche thing, and would be of limited interest to most readers, I expect. But if you disagree, let me know. Maybe I can go into greater detail on handler authoring in a longer-form blog post or something, if it’s interesting to folks.


Share this

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

Unsure? Browse the archive .

Related Content


Test logging with ReplaceAttr

Today’s topic is probably the most interesting, subtle, and complicated of the three HandlerOptions fields: ReplaceAttr. type HandlerOptions type HandlerOptions struct { … // ReplaceAttr is called to rewrite each non-group attribute before it is logged. // The attribute's value has been resolved (see [Value.Resolve]). // If ReplaceAttr returns a zero Attr, the attribute is discarded. // // The built-in attributes with keys "time", "level", "source", and "msg" // are passed to this function, except that time is omitted // if zero, and source is omitted if AddSource is false.


Handler level

Each handler has an optional Level value, which controls which logs to drop, and which to actually log: type HandlerOptions type HandlerOptions struct { … // Level reports the minimum record level that will be logged. // The handler discards records with lower levels. // If Level is nil, the handler assumes LevelInfo. // The handler calls Level.Level for each record processed; // to adjust the minimum level dynamically, use a LevelVar.


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