koukiblog

たぶんweb系の話題

GolangでGKE用(StackdriverLogging)のログを出力する

GKE(Google Kubernetes Engine)でアプリケーションを開発する場合、ログは標準出力に出力し、GKEデフォルトでインストールされるfluentdでStackdriverLoggingに出力することが多いと思います。

その場合、特定のJSONフォーマットで出力することでStackdriverLogging上で扱いやすくなります。フォーマットの詳細はこちらです。 https://cloud.google.com/logging/docs/agent/configuration#special-fields

Golangの場合、デフォルトのLoggerでは

という問題があったので、どうすればよいのか調べてみました。

まず、ログ用のライブラリですが、logrusというライブラリを使うのがよさそうでした。 https://github.com/sirupsen/logrus

構造化したログを扱うことができ、フォーマットも指定することができます。

JSONのFormatterは標準で用意されているので下記のように利用することでJSON形式でログを出力することが可能です。init() でformatterを指定している箇所で環境変数を使った分岐を使えば、手元ではテキスト形式、サーバではJSONという分岐も可能です。

import (
    "os"
    log "github.com/sirupsen/logrus"
)

func init() {
    // Log as JSON instead of the default ASCII formatter.
    formater := log.JSONFormatter{
        FieldMap: log.FieldMap{
            log.FieldKeyLevel: "severity",
        },
    }

    log.SetFormatter(&formater)

    // Output to stdout instead of the default stderr
    log.SetOutput(os.Stdout)

    // Only log the warning severity or above.
    log.SetLevel(log.InfoLevel)
}

func main() {
  log.Info('hello') // => {"msg": "hello", "level":info, "time":"2019-11-24T18:06:23+09:00"}
}

StackdriverLoggingに連携するにあたって、levelは、"severity"というkeyで連携する必要があります。これは、JSONFormaterにFieldMapを指定することで実現できます。

func init() {
    // Log as JSON instead of the default ASCII formatter.
    formater := log.JSONFormatter{
        FieldMap: log.FieldMap{
            log.FieldKeyLevel: "severity",
        },
    }

    log.SetFormatter(&formater)
}

この解決策は、下記Issueで紹介されていました

github.com

また、logrusで用意されているレベルとStackdriverLoggingで定義されているレベルには差異があるので、カスタムレベルを定義する方法があれば、それを利用したいところですが、logrusには用意されていないようでした。info, warning,errorは利用できますが、それ以外を利用するとStackdriverLoggingでは正しく扱えないので注意が必要です。 それぞれがサポートしているレベルは下記です。

StackdriverLogging: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity

logrus: https://github.com/sirupsen/logrus/blob/39a5ad12948d094ddd5d5a6a4a4281f453d77562/logrus.go#L27

Custom Log Levelについては、Issueで要望があがっていますが、いまのところ実装される見込みは薄そうです。

github.com

ということで手軽にJSON形式のログを出力する場合はlogrusがおすすめです。Golang標準のloggerインターフェースを実装しているので、後から差し替えるのも簡単だと思います。