log/slogの使い方

key=valueで属性を追加したり、ログレベルの設定、メッセージを持ったログレコードを構造化したログパッケージ

slogはLogger型を持っており、この方はLogger.Info
やLogger.Error
といったメソッドをいくつか持っている

ログレコードは時刻、ログレベル、メッセージとkey-valueのセットで表現される。
slog.Info("Hello", "count", 3)
2024/01/05 19:59:24 INFO Hello count=3

デフォルトのハンドラを使うと出力はlog
パッケージに渡されるので、もしフォーマットを独自のものにしたい場合はハンドラを自分で定位する必要がある。
テキスト形式でフォーマットする場合
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
logger.Info("Hello", "count", 2)
time=2024-01-05T20:06:37.485+09:00 level=INFO msg=Hello count=2
JSON形式でフォーマットする場合
jsonLogger := slog.New(slog.NewJSONHandler(os.Stderr, nil))
jsonLogger.Info("Hello", "count", 3)
{"time":"2024-01-05T20:13:26.037274619+09:00","level":"INFO","msg":"Hello","count":3}

作成したハンドラをデフォルトとして扱いたい場合はslog.SetDefault(logger)
を呼ぶことで設定できる
slog.SetDefault(jsonLogger)
slog.Info("default change", "count", 4)
{"time":"2024-01-05T21:15:32.806772913+09:00","level":"INFO","msg":"default change","count":4}

共通で出力する属性の追加もできる。例えばWEBアプリケーションでリクエストのメソッドをログに常に出しておきたいといった場合は以下のようにLogger.With
を使うことで追加可能
logger2 := jsonLogger.With("method", r.Method)
logger2.Info("request start")
{"time":"2024-01-05T21:22:56.880100509+09:00","level":"INFO","msg":"request start","method":"GET"}

ログレベルの設定はハンドラ作成時の引数slog.HandlerOptions
のLevelを設定することで行う。
LevelはLeveler
というインターフェースで、これはslog.LevelVar
のポインタが実装しているのでこの型のポインタ変数を用意することで行える。コードは以下
// ログレベルの設定
var programLevel = new(slog.LevelVar)
h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel})
slog.SetDefault(slog.New(h))
programLevel.Set(slog.LevelDebug)
slog.Debug("display!")
slog.Info("display!")
programLevel.Set(slog.LevelInfo)
slog.Debug("no display!")
slog.Info("display!")
{"time":"2024-01-05T21:45:07.312730299+09:00","level":"DEBUG","msg":"display!"}
{"time":"2024-01-05T21:45:07.312731762+09:00","level":"INFO","msg":"display!"}
{"time":"2024-01-05T21:45:07.312740409+09:00","level":"INFO","msg":"display!"}

属性をひとまとめにするためにグループというものが存在する。
TextHandler
ではグループと属性は.(ドット)で分かれる。JSONHandler
ではJSONオブジェクトとして扱われる。
slog.Info("Hell", slog.Group("request", "method", r.Method, "url", r.URL.String()))
# TextHandlerの場合
time=2024-01-05T22:04:21.137+09:00 level=INFO msg=Hello request.method=GET request.url=https://example.com
# JSONHandlerの場合
{"time":"2024-01-05T22:03:14.181568376+09:00","level":"INFO","msg":"Hell","request":{"method":"GET","url":"https://example.com"}}
Logger.With
のように、共通のグループを付与したい場合はLogger.WithGroup
で可能

context.Context
などから情報を取得したい場合、Logger.InfoContext
がある。

Attr
はkey-valueのペア。
Loggerのメソッドはkeys/valueのかわりとしてAttrを受け付ける。
例えば以下は同じコードを意味する
slog.Info("hello", slog.Int("count", 3))
slog.Info("hello", "count", 3)