Go で cronolog ライクにファイル作成・ログ出力するパッケージ

github.com

を書いてみた。似たものはあったけど、ピンポイントで欲しいものではなかったし、せっかくなので Go の勉強も兼ねて作った。

仕様

引数で受け取ったフォーマット文字列を、現在時刻に置き換えてファイルパスにする。
ファイルパスに含まれるディレクトリもなければ作成して、ファイルに文字列を出力する。

フォーマットは下記例のとおり。

入力フォーマット 出力パス
/path/to/example.log.%Y%m%d /path/to/example.log.20170205
/path/to/%Y/%m/%d/example.log /path/to/2017/02/05/example.log

だいたい cronolog にならっていて、時間をベースにファイル分割していく。

使い方

せっかくなので使い方も書いておく。
基本は、Logger と組み合わせて使う。
例えば、uber-go/zap と組み合わせるときは、👇🏼 のとおり Writer オブジェクトをつくって io.Writer の受け口に渡してあげるだけ。

package main

import (
    "github.com/uber-go/zap"
    "github.com/utahta/go-cronowriter" // 👈🏼
)

func main() {
    w1 := cronowriter.MustNew("/tmp/example.log.%Y%m%d") // 👈🏼
    w2 := cronowriter.MustNew("/tmp/internal_error.log.%Y%m%d") // 👈🏼
    l := zap.New(
        zap.NewJSONEncoder(),
        zap.Output(zap.AddSync(w1)),
        zap.ErrorOutput(zap.AddSync(w2)),
    )
    l.Info("test")
}

// Output:
// /tmp/example.log.20170204
// {"level":"info","ts":1486198722.1201255,"msg":"test"}

他の Logger と組み合わせるときも、同じように io.Writer に渡す。
interface 便利!

オプション

いろいろオプションも用意していて、たいていのものは揃えた。

WithLocation

タイムゾーンの設定。デフォルトはシステムロケール。

w := cronowriter.MustNew("/path/to/example.log.%Z", cronowriter.WithLocation(time.UTC))
// /path/to/example.log.UTC

WithSymlink

シンボリックリンクの設定。現在書き込み対象のファイルに対してシンボリックを貼る。

w := cronowriter.MustNew(
    "/path/to/example.log.%Y%m%d", 
    cronowriter.WithSymlink("/path/to/example.log")
)
// /path/to/example.log -> /path/to/example.log.20170218

WithMutex

排他制御する設定。大抵の Logger は write 前で mutex.Lock していることから writer はデフォルトで排他制御しなくした。

w := cronowriter.MustNew("/path/to/example.log.%Y%m%d", cronowriter.WithMutex())

WithDebug

デバッグ機能。ファイル書き込みと同時に標準出力する。

w := cronowriter.MustNew("/path/to/example.log.%Y%m%d", cronowriter.WithDebug())

WithInit

writer を New したときにファイルを作成する。デフォルトは Write が呼ばれたタイミングでファイルを作成している。
書き込み権限があるかどうか事前に知りたいとき使うと便利。

w := cronowriter.MustNew("/path/to/example.log.%Y%m%d", cronowriter.WithInit())

echo で使われてる logger のベンチマークをとってみた

uber-go/zap との比較が目的なので、zap のベンチマークテストと同じようなコードを書いてとってみた。

元々あったテスト(BenchmarkLog-4)と大して変わらない結果。

uber-go/zap

uber-go/zap のベンチマークを同じマシンで実行した結果。

$ go test -bench .
...
BenchmarkNoContext-4                             5000000               283 ns/op
BenchmarkBoolField-4                             5000000               344 ns/op
BenchmarkFloat64Field-4                          3000000               403 ns/op
BenchmarkIntField-4                              5000000               359 ns/op
BenchmarkInt64Field-4                            5000000               361 ns/op
BenchmarkStringField-4                           5000000               346 ns/op
BenchmarkStringerField-4                         5000000               368 ns/op
BenchmarkTimeField-4                             5000000               363 ns/op
BenchmarkDurationField-4                         5000000               371 ns/op
BenchmarkErrorField-4                            5000000               361 ns/op
...

なんだか圧倒的に早い。