log の Writer を Discard してみる

golang のログ難しい・・・

golang.org

特定のログレベルが指定されたときだけログ出力を有効化できるようになっているといいんじゃないかと思った。 ほんとはもっと自由に設定できるようになって欲しいけど。

とりあえずの実装はこんな感じ。 環境変数 LOG_LEVELdebug が指定されたら出力する、それ以外では出さない。

io.Writer な変数( ioutil.Discard から推論されてるはず) に *os.Fileos.Stdout を代入できるのは (*File) Write があるからだと思う。 プロジェクト固有の実装でこういうのがあったら辛いなぁ。

package main

import (
    "io/ioutil"
    "log"
    "os"
)

var logger *log.Logger

func init() {
    writer := ioutil.Discard
    if os.Getenv("LOG_LEVEL") == "debug" {
        writer = os.Stdout
    }
    logger = log.New(writer, "[main] ", log.LstdFlags)
}

func Log() {
    logger.Println("aaabbbccc")
}

ログ出力が無効な状態で性能落ちてもいやなので、簡単にベンチマーク

package main

import (
    "testing"
)

func BenchmarkLog(b *testing.B) {
    for n := 0; n < b.N; n++ {
        Log()
    }
}

これを環境変数指定して2回実行。

go test -bench=. > discard_bench.txt
LOG_LEVEL=debug go test -bench=. > stdout_bench.txt

そうすると次のような感じになった。 ざっくり 14 倍のオーバーヘッド (5169/361 = 14.3)。 プロジェクトの都合で使ってるロギングライブラリがあるときはダメだけど、そうでなければなんか利用できそう。

実行方法 繰り返し回数 呼び出しあたりの時間
無効化 5,000,000 361 ns/op
有効化 200,000 5169 ns/op