こんにちは。HDEクラウドプロダクト開発部 小本です。
昨年はGo言語が大盛り上がりでした。HDEでも新規サービスをGo言語で書いています。
しかし、先日リリースされたaws-sdk-goなどについては諸先輩方が書いてくださると思うので、 私は重箱の隅つつきのようなことを書こうと思います。
今日書くのは、私のチームではGo言語標準のlog
を(多少のラッパー関数経由で)使っていたのですが、
実はLogrus(https://github.com/Sirupsen/logrus)が、かなり便利だったという話です。
標準のlog
は貧弱
エラーレベル(Debug, Info, Warn, Error等)が無いのも問題ですが、
ログをPrintf
などで自分で整形しなければいけないのも問題です。
つまり・・・
// 悪い例1 log.Printf(`some error occured level=%s method=%s path=%s host=%s status=%s bytes=%s\n`, `error`, `GET`, `/`, `example.com`, `200 OK`, 10234) // 悪い例2 msg := "some error occured " fields = map[string]string { "level": "info", "method": "GET", "path": "/", "host": "example.com", "status": "200", "bytes": "10234", } for k, v := range fields { msg += fmt.Sprintf(" %s=%s", k, v) } log.Println(msg)
書捨てコードならともかく、コード量が多くなると一々書くのはおっくうです。
また、「後からログのフォーマットを変更したいときはどうするのか?」 「そもそもどんなフォーマットで出力するのか?」という問題もあります。
そしてバグ発覚時に「ここでログを出しておけば・・・」と後悔するでしょう。
これらの問題はlog
以外のサードパーティのログライブラリにも同様に存在します。
Logrusはフォーマット指定が不要
一方、LogrusはパラメータをWithFields
で渡すだけ。フォーマットは後から簡単に変更できます。
つまり 「とりあえず全部JSONで出力しとけばいっか」 → 後から必要に応じて変更 といった遅延評価が可能です。
logrus.SetFormatter(&logrus.JSONFormatter{}) logrus.WithFields(logrus.Fields{ "level": "info", "method": "GET", "path": "/", "host": "example.com", "status": 200, "bytes": 10234, }).Info("some error occured") // => {"level": "info", "method": "GET", "path": "/", "host": "example.com", "status": 200, "bytes": 10234}
またLogrusには標準でJSON形式・テキスト形式(logfmt)が付属していますが、 メソッドを一つ実装するだけで簡単に新しい出力フォーマットを自作できます。
type Formatter interface { Format(*Entry) ([]byte, error) }
というわけで、LTSV用フォーマッタを作ってみました。
doloopwhile/logrusltsv · GitHub
LTSV(Labeled Tab-Separated Values)フォーマットは、 シェルスクリプトでも扱えるほどシンプルな上、後からフィールドを追加するのも簡単。 fluentd等のツールも対応しており、JSONを上回る「とりあえずこれでいいか」力を持っています。
そのためHDEの一部製品でもLTSVを使っています。
あとがき
HDEでは勉強会スペースの貸し出しをしております。 ぜひご利用ください。