Overriding the default handler

April 8, 2026

Today I’m going to jump around a bit in the GoDoc, to talk about a topic I mentioned last time: how to override the default logger.

Overview

Setting a logger as the default with

slog.SetDefault(logger)

will cause the top-level functions like Info to use it. SetDefault also updates the default logger used by the log package, so that existing applications that use log.Printf and related functions will send log records to the logger’s handler without needing to be rewritten.

While I generally discourage use of the default logger, for reasons I’ll get into another day, if you have an application that uses either the default log handler or the default log/slog handler, you can at least control how it works!

file, err := os.Open("/var/log/myapp.log")
if err != nil {
  panic(err)
}
logger := slog.New(slog.NewJSONHandler(file, nil))
slog.SetDefault(logger)

// Some time later...

slog.Info("Interesting things are afoot!") // Written to /var/log/myapp.log

// Meanwhile, back at the farm...

log.Printf("And then he turned to me and said...") // Also written to /var/log/myapp.log

Share this

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

Unsure? Browse the archive .

Related Content


Concurrent logging

One last note in the performance section… How does logging work in a concurrent system? Performance considerations … The built-in handlers acquire a lock before calling io.Writer.Write to ensure that exactly one Record is written at a time in its entirety. Although each log record has a timestamp, the built-in handlers do not use that time to sort the written records. User-defined handlers are responsible for their own locking and sorting.


Back after an unannounced absence

Hey everyone… I dropped the ball! A combination of unexpected family events, prepping for a conference, and some travel, meant I haven’t been writing for much longer than I like. But I’m back! So where were we? Oh that’s right… performance considerations with log/slog. We had looked at using the fmt.Stringer interface to avoid eager processing with slog.TextHandler. But let’s now look at a more general solution: Performance considerations …


Lazy attribute evaluation for JSONHandler

As I was writing yesterday’s post, a portion of the GoDoc confused me. I’ve now spent over 3 hours with Claude trying to parse the prose grammatically, build test cases, and make general sense of it. I think I finally have… Here’s hoping! So, yesterday we saw how you can lazy-evaluate some values when using TextHandler. But the proposed solution (pass a fmt.Stringer rather than a literal string) has other, likely uninintended, consequences if you’re using JSONHandler:

Get daily content like this in your inbox!

Subscribe