このたび、slogerrというライブラリをリリースしました。
モチベーション
uber-go/zapの Error 関数のように、エラー型に付加情報があればついでにログ出力のattributeに含めてくれるものが欲しくて作りました。
slogでエラーを出力する場合、大抵は slog.String("error", err.Error()) のようにエラーを文字列化するか slog.Any("error", err) のようにany型として取り扱うか、の2択だと思います。エラーを文字列化する場合、エラー型が %+v によるフォーマットに対応している場合でも、シンプルなエラーメッセージしかログに残りません。any型として扱う場合も同様です。
使い方
slogerrが提供する関数は2つだけです。
func Error(err error) slog.Attr func NamedError(key string, err error) slog.Attr
以下のように、ログ出力時のattributeとして slogerr.Error(...) 関数の呼び出し結果を渡してあげればよいです。
slog.ErrorContext("failed", slogerr.Error(err)) // => {"msg":"request failed","error":{"msg":"something went wrong"}}
普通に使う範囲であれば、ログのattribute名を決めなくてよいとか、出力されるのが単なる文字列からオブジェクトに変わったとか、それぐらいでは? と思われるかもしれません。
slogerrが本領を発揮するのは、スタックトレース情報つきのエラー*1や、errors.Join 関数で複数のエラーがjoinしたようなエラーを出力するときです。verbose フィールドにスタックトレースを含むエラーメッセージが表示されたり、causes フィールドにjoinされた複数のエラーが個別に表示されたりするようになります。
{"msg":"request failed","error":{"msg":"something went wrong","verbose":"something went wrong\nmain.main()\n\t/app/main.go:42"}}
{"msg":"request failed","error":{"msg":"db error\ntimeout","causes":{"0":{"msg":"db error"},"1":{"msg":"timeout"}}}}
(2026/6/12 0:34 追記) 渡したエラーが slog.LogValuer を実装している場合は (つまり、元々slogでログ出力するように作られている場合は) msg verbose causes のようなフィールドを追加するのではなく、元々のエラーが返すattributesを出力するようにしました。
(追記ここまで)
実装
APIインタフェースはuber-go/zapを大いに参考にしました。
ほぼ全ての実装をClaude Codeにやってもらいました。zapの Error NamedError のようなインタフェースをslogでも使えるようにしたい、アイデアを大いに参考にしているので著作権表記を入れておいて*2、ぐらいしか指示していなかったと思います。あとはベンチマークを書いてもらい、アロケーションを減らしてほしいと頼んだぐらい?
エラーにスタックトレースが乗っていたら実際に抽出する、みたいなことも検討したけど、大抵のエラーライブラリは %+v によるフォーマットに対応しているのでこれでいいじゃん、と見切りをつけました。
- pkg/errors*3: https://github.com/pkg/errors/blob/87f8819acf6dc28bf5d3c14b334268236d686f48/errors.go#L129-L133
- xerrors: https://cs.opensource.google/go/x/xerrors/+/7835f813:adaptor.go;l=45-47
- cockroachdb/errors: https://github.com/cockroachdb/errors/blob/fc93249bf0c739ca6f4dcac20260d52302d3e3a3/errbase/format_error.go#L97
- samber/oops: https://github.com/samber/oops/blob/c57d8644bc0dd7ca0c0ac22ae5cf37075f1e7c44/error.go#L797-L800
おわりに
どうぞご利用ください。早速、自分がメンテナンスしているOSSに導入してみています。