私が歌川です

@utgwkk が書いている

slogでエラーをちょっとリッチにログ出力するためのライブラリ slogerr をリリースした

このたび、slogerrというライブラリをリリースしました。

github.com

モチベーション

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 によるフォーマットに対応しているのでこれでいいじゃん、と見切りをつけました。

おわりに

どうぞご利用ください。早速、自分がメンテナンスしているOSSに導入してみています。

github.com

github.com

*1:大抵 %+v によるフォーマットをサポートしている

*2:こういう対応で必要十分なのかはそこまで自信がない、何も書かないより遥かにマシだと思っているけど、自信のある方がいたら教えてください

*3:さすがにもう古い気はする

時間のないサイト運営者リング