nがひとつ多い。

えぬなおの技術的なことを書いていくとこ。

【Go】zapで出力時のLevelに色をつける

zapって?

uber社が作っているgolangで使う超いけてるログドライバ。

github.com

基本というかほとんどの日本語情報は以下を見ればいい。

qiita.com

構造化されたログを吐き出す癖にあらゆる非構造化ログドライバより速いらしい。
(真面目な話、非構造化ってことは往往にして型をリフレクトして結合してるんだからそっちの方が遅いのはそりゃそうか)

いつの間にレベルのカラライズやれるようになっていた

あい。

https://cloud.githubusercontent.com/assets/4228796/23066336/537fe9dc-f51a-11e6-8ec7-0a29f8e9cc38.png

ちゅーか、2年前くらいからもうimplされてるみたいだから相当昔からサポートされていることになる。

github.com

しかし日本語の情報でこれについて書いてる記事ないし、書くかーーーーってなった。

どうやるのかー。

EncoderConfigEncodeLevelCapitalColorLevelEncoder を指定すればいい

var StdLogger *zap.Logger

func InitLogger() error {
    var err error

    level := zap.NewAtomicLevel()
    level.SetLevel(zapcore.DebugLevel)

    myConfig := zap.Config{
        Level:    level,
        Encoding: "console",
        EncoderConfig: zapcore.EncoderConfig{
            TimeKey:        "Time",
            LevelKey:       "Level",
            NameKey:        "Name",
            CallerKey:      "Caller",
            MessageKey:     "Msg",
            StacktraceKey:  "St",
            EncodeLevel:    zapcore.CapitalColorLevelEncoder, // ここをzapcore.CapitalLevelEncoderじゃなくてzapcore.CapitalColorLevelEncoderをつかう。
            EncodeTime:     zapcore.ISO8601TimeEncoder,
            EncodeDuration: zapcore.StringDurationEncoder,
            EncodeCaller:   zapcore.ShortCallerEncoder,
        },
        OutputPaths:      []string{"stdout"},
        ErrorOutputPaths: []string{"stderr"},
    }

    StdLogger, err = myConfig.Build()
    return err
}

注意点

この色つけには注意点があって、この カラライズはコンソール出力に限らず実行される と言うことだ。 これはどう言うことかと言うと、↑のコードの内 myConfig を以下のようにし、

    myConfig := zap.Config{
        Level:    level,
        Encoding: "json",
        EncoderConfig: zapcore.EncoderConfig{
            TimeKey:        "Time",
            LevelKey:       "Level",
            NameKey:        "Name",
            CallerKey:      "Caller",
            MessageKey:     "Msg",
            StacktraceKey:  "St",
            EncodeLevel:    zapcore.CapitalColorLevelEncoder, // ここをzapcore.CapitalLevelEncoderじゃなくてzapcore.CapitalColorLevelEncoderをつかう。
            EncodeTime:     zapcore.ISO8601TimeEncoder,
            EncodeDuration: zapcore.StringDurationEncoder,
            EncodeCaller:   zapcore.ShortCallerEncoder,
        },
        OutputPaths:      []string{"stdout"},
        ErrorOutputPaths: []string{"stderr"},
    }

吐き出すフォーマットをjsonにすると、

{"Level":"\u001b[34mINFO\u001b[0m","Time":"2019-02-25T11:32:15.845+0900","Caller":"cache/redis.go:40","Msg":"REDIS","msg":"Connecting Redis Parameter is tcp0.0.0.0:6379"}
{"Level":"\u001b[34mINFO\u001b[0m","Time":"2019-02-25T11:32:15.845+0900","Caller":"cache/redis.go:41","Msg":"REDIS","msg":"REDIS_MAX_IDLE is 3"}
{"Level":"\u001b[34mINFO\u001b[0m","Time":"2019-02-25T11:32:15.845+0900","Caller":"cache/redis.go:42","Msg":"REDIS","msg":"REDIS_MAX_ACTIVE is 1000"}
{"Level":"\u001b[34mINFO\u001b[0m","Time":"2019-02-25T11:32:15.845+0900","Caller":"cache/redis.go:43","Msg":"REDIS","msg":"REDIS_IDLE_TIMEOUT_SECONDS is 240"}

エスケープシーケンスがそのままJSONに乗ってしまうので注意されたい。
仮に出力フォーマットがjsonの場合、エスケープシーケンスが色として意味をなしたとしてJSONの値に色つけされた所で嬉しい事はないでしょうしまぁゴミが入ってる状態と思っていい。
環境ごとに zapcore.CapitalLevelEncoderzapcore.CapitalColorLevelEncoder を使い分けるコードをオススメされたい。