Shogo's Blog

Sep 10, 2023 - 1 minute read - go golang

log/slogにログを転送する logrus hook を書いた

長らく構造化ログの仕組みが標準ライブラリになかったGoですが、 Go 1.21がリリースされて晴れて log/slog が使えるようになりました。 弊社ではlogrusを使っているので、log/slogを連携するためのフックを書きました。

背景

弊社ではlogrusをメインに使っています。 特段困ったこともなく 素晴らしいライブラリだと思います!!!(大事) 強いて問題点を上げるとすれば、メンテナンスモードに入ってしまってあまり開発が活発でない、ということでしょうか。 重大なバグがあれば別ですが、新規機能の追加等は行わない方針のようです。

一方 log/slog は公式ライブラリなので、log/slogの仕様を前提としたエコシステムが、今後発展してくでしょう。

logrusを使いながらlog/slogのいいとこ取りとする方法はないか?と考えた結果作ったのが shogo82148/logrus-slog-hook です。

SYNOPSIS

sloghook.New で作成したフックを差し込むだけです。 logrusに流したログがlog/slogの設定で流れてきます。

package main

import (
	"io"
	"log/slog"
	"os"

	sloghook "github.com/shogo82148/logrus-slog-hook"
	"github.com/sirupsen/logrus"
)

func main() {
	h := slog.NewTextHandler(os.Stderr, nil)
	logrus.AddHook(sloghook.New(h))

	// logrus も logrus-slog-hook もSTDERRに書き込むので、同じログが二回表示されてしまう。
	// logrus側を止めて防止。
	logrus.SetFormatter(sloghook.NewFormatter())
	logrus.SetOutput(io.Discard)

	logrus.WithFields(logrus.Fields{
		"name": "joe",
		"age":  42,
	}).Error("Hello world!")

	// Output:
	// time=2023-09-10T23:32:41.229+09:00 level=ERROR msg="Hello world!" age=42 name=joe
}

注意点

logrusはエラーレベルが Trace, Debug, Info, Warn, Error, Panic, Fatal と7段階ありますが、 log/slogには Debug, Info, Warn, Error しかありません。 しかし実は整数をレベルを設定できるので、適当に割り当てました。

  • logrus: slog
  • trace: DEBUG-1
  • debug: DEBUG
  • info: INFO
  • warn: WARN
  • error: ERROR
  • panic: ERROR+1
  • fatal: ERROR+2

ログに出力されるエラーレベルもこれになるので、ログを監視するようなツールを導入していると修正が必要がかもしれません。

まとめ

log/slogを連携するlogrusのフックを書きました。 log/slogの便利機能を取り込んだり、log/slogへの移行に使用できると思うので、 ぜひ利用してください。