Let's talk about logging

March 31, 2026

I’ve been absent far too long. Most days I think about writing something again, then… I don’t. 🤷‍♂️ I’m going to try to get back into the habit… and this time, I thought I’d talk about one of my favorite packages in the standard library: log/slog.

To kick off, I’ll give a general description of the package, then starting tomorrow (I promise! I won’t forget again!) we’ll start into the particulars.

First there was log

The log package has been with us since the very beginning of Go. But few use it for serious applications, because it’s so limited. No real log levels–just “info” (or info + panic, or info + os.Exit), plain text output (no JSON or other formats), and thus no meaningful middleware capabilities.

These limitations lead to the proliferation of many third-party logging libraries such as Logrus, Zap, and ZeroLog.

Introducing log/slog

Finally, in June, 2023, with Go 1.21, log/slog was introduced. And now, except for very special cases, it should probably be your go-to logger. It offers:

  • LevelsDebug, Info, Warn, and Error by default, but it’s customizable, so you can also have Super Duper Important I really Mean it, I do! as a level, if you want!
  • Structured output — Key/value pairs for the win!
  • Pluggable handlers — Want JSON output? Handled. Standard text more to your liking? You got it. Want color on the console? No problem.
  • Composable handlers — Want JSON sent to your logging service, plain text to your log file, and color to your console, all at the same time? We have that, too!
  • Middleware — Want to filter passwords out of your logs? Or add special annotations to every error? Or replace every occurrence of the word “hippopotamus” with “rhinoceros” for unexplicable reasons? You can.

If you’ve never used log/slog, this series will be for you.

If you already use log/slog, you’ll probably learn something new anyway!

So let’s go!


Share this

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

Unsure? Browse the archive .

Related Content


More with Groups

Organizing log key/value pairs by group is a nice way to organize your logging data, but what about organizing the way your application groups data? Maybe you want all logs created by a particular code path to be grouped together. How can you accomplish this? Enter WithGroup… Groups … Use Logger.WithGroup to qualify all of a Logger’s output with a group name. Calling WithGroup on a Logger results in a new Logger with the same Handler as the original, but with all its attributes qualified by the group name.


Groups

Early bird registration for [**Idiomatic Testing in Go**](/idiomatic-testing/) ends today! Not sure how to adapt your xUnit habits to Go? This is the course for you! Sign up today to save 25% over the full price. – Sometimes you want to group several key/value attributes together when logging. Maybe different aspects of an error (error_code, error_detail, stacktrace, etc), or different aspects of an HTTP response (bytes_sent, status_code, etc). The log/slog package gives us this!


Filtering logs by level

Levels In an application, you may wish to log messages only at a certain level or greater. One common configuration is to log messages at Info or higher levels, suppressing debug logging until it is needed. The built-in handlers can be configured with the minimum level to output by setting [HandlerOptions.Level]. The program’s main function typically does this. The default value is LevelInfo. Pretty straight forward, eh? Only want to log Info-and-above inproduction?

Get daily content like this in your inbox!

Subscribe