SlideShare a Scribd company logo
Goのロギング周りの考
察
株式会社ホワイトプラス システム開発Gマネジャー 大和屋貴仁
Go Conference 2017 Autumn
OSSで採用されているロギング
大和屋貴仁
株式会社ホワイトプラス
システム開発G マネジャー
Microsoft MVP for Azure(2011-2018
Qiita : @t_Yamatoya
http://sqlazure.jp/r
富士フィルムイメージングシステムズと
共同開発したRFID検証。
宅配ネットクリーニングのリネット
会員数20万人突破!
Golang、RFIDなど新しい技術や物を活用したサービス改善に興味のあるエンジニア募集!!
今日のお話
標準logパッケージの特徴
OSSのロギング事情
利用しているロギングライブラリ
Golangのロギング事情について調べてみまし
た
アプリを書くときのロギング実装の参考になれば幸い
SRE サイトリライアビリティエンジニアリング
――Googleの信頼性を支えるエンジニアリングチーム
Prometheusは、特にルール言語にBorgmonと多くの類似
点があります。
依然としてBorgmonはGoogle内部のものですが、ア
ラートを発するためのデータソースとして時系列デー
タを扱うという発想は、今日ではPrometheus、Riemann、
Heka、Bosunといったオープンソースのツールを通じ
て広く受け入れられており…
Prometheus と google
SRE サイトリライアビリティエンジニアリング
――Googleの信頼性を支えるエンジニアリングチーム
Prometheus 入門から運用まで徹底解説
Logging for Prometheus
1通のメールが発端
Fabian Reinartz
ドイツ ベルリン
2016/04- CoreOS
2015/09-2016/03 SoundCloud/Prometheus
2017年08月10日
To: Prometheus Developers Group
Instead I just want to serve Brian's request to discuss our logging
library usage.
Triggered was this by me using Go kit's logging package in
prometheus/tsdb rather than our so far canonical
prometheus/common/log package.
Prometheusで使用するロギングライブラリについて議論したい。
tsdbではGo kitを使用してたよね。
Prometheusの実装的なお話し
prometheus/tsdb
PrometheusのTime Series Database
ストレージレイヤー
prometheus/Prometheus
メイン実装 prometheus/common/log
github.com/go-kit/kit/log
異なるロギングライブラリを使用している
Prometheusの実装的なお話し
prometheus/tsdb
PrometheusのTime Series Database
ストレージレイヤー
prometheus/Prometheus
メイン実装
prometheus/common/log
github.com/go-kit/kit/log
1つのメソッドをもつインターフェイスがベース
ロギングライブラリを完璧にラッピングしている
18のメソッドをもつ複雑なインターフェイス
ロガーをプラグインで使用してもらうには、Go Kitライブラリは便利。common/logは年月を経て、いろんな副作用
を内在してしまっている。
Prometheusのロギング変更に関する意見
・2種類のライブラリを使用するのは混乱の元なので一貫性が気になる。
・強いこだわりはない
・tsdbはできるだけ一般的でPrometheus固有でないロギングインターフェイスを使用する必要がある
・Go Kit と作者はGo Communityに強い影響力を持っているので一般的に採用可能で、
将来的にも問題ないかな
Switch to go-kit log #3061
https://github.com/prometheus/prometheus/pull/3061
Logging : Go Kit
Gokitのロギング仕様ブック
https://docs.google.com/document/d/1shW9DZJXOeGbG9Mr9Us9MiaPqmlcVatD_D8lrOXRNMU/edit#
Log パッケージで不便な点
とてもシンプルなパッケージ
・非構造体(Printスタイル)
・限定的な設定項目
時間や日付の出力単位
ログの出力パスの指定
・loggerは型で定義されている
・グローバルloggerオブジェクトが提供される
Log パッケージで困ること
・型で定義されているので、別の実装を提供しにくい
・グローバルloggerオブジェクトを呼び出す関数が存在する
インポートしたライブラリのロギングを制御しにくい
・レベル付きロギングが欲しい
debug、info、warn、error
Dave Chene
シドニーのプログラマ
2011年2月からGoのコントリビューター
2011年4月からGoのコミッター
非公式の調査:Goアプリケーションのロギング状況
https://groups.google.com/forum/#!msg/golang-dev/F3l9Iz1JX4g/BOBpbhF-FAAJ
大きく次の3種類のルートを選択している
・fmt.Printf
・logパッケージから関数を使用する
・パッケージレベルのログ変数の宣言
非公式の調査:Goアプリケーションのロギング状況
https://groups.google.com/forum/#!msg/golang-dev/F3l9Iz1JX4g/BOBpbhF-FAAJ
というわけでサードパーティ
乱立するロギングライブラリ
golang/glog
inconshreveable/log15
sirupsen/logrus
uber-go/zap
go-kit/go
ロギングは常時付いて回る
乱立していると、どのライブラリを使用すると良いのか悩む
Prometheusのロギング
go-kit/kit/log
github.com/go-kit/kit/log
promlog/log.go でゆるーくラッピングしている
func New(al AllowedLevel) log.Logger {
l := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
l = log.With(l, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller)
return l
}
Prometheusのロギング
go-kit/kit/log
github.com/go-kit/kit/log
key/value形式の構造化ロギング
レベル付ロギング
文脈情報の付加
JSONフォーマット、テキストフォーマットの出力
Prometheusのロギング
go-kit/kit/log
github.com/go-kit/kit/log
logger.Log("transport", "HTTP", "addr", addr, "msg", "listening")
key/value形式で指定する構造化ログ
var logger log.Logger
logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
logger = log.With(logger, "instance_id", 123)
logger.Log("msg", "starting")
文脈情報の付加
instance_id=123 msg=starting
Prometheusのロギング
go-kit/kit/log
github.com/go-kit/kit/log
var logger log.Logger
logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller)
logger.Log("msg", "hello")
呼び出し元と時間情報の付加
ts=2016-01-01T12:34:56Z caller=main.go:15 msg=hello
Syncthinsのロギング
log
標準パッケージ
log.Println("Lstat:")
log.Printf(" Size: %d bytes", fi.Size())
log.Printf(" Mode: 0%o", fi.Mode())
log.Printf(" Time: %v", fi.ModTime())
log.Printf(" %d.%09d", fi.ModTime().Unix(), fi.ModTime().Nanosecond())
log.Println()
func main() {
log.SetFlags(0)
log.SetOutput(os.Stdout)
Goの標準ライブラリのlogパッケージをそのまま利用。
Terraformのロギング
オリジナル:logutils
github.com/hashicorp/logutils
Goのエコシステムを断片化せずに
標準ライブラリのlogパッケージを拡張して少しモダンにします
→ Logパッケージを使用したまま、logutilsに切り替え可能
package main
import (
"log"
)
func main() {
log.Print("[DEBUG] Debugging")
log.Print("[WARN] Warning")
log.Print("[ERROR] Erring")
log.Print("Message I haven't updated")
}
github.com/hashicorp/logutils
package main
import (
"log"
"os"
"github.com/hashicorp/logutils"
)
func main() {
filter := &logutils.LevelFilter{
Levels: []logutils.LogLevel{"DEBUG", "WARN", "ERROR"},
MinLevel: logutils.LogLevel("WARN"),
Writer: os.Stderr,
}
log.SetOutput(filter)
log.Print("[DEBUG] Debugging")
log.Print("[WARN] Warning")
log.Print("[ERROR] Erring")
log.Print("Message I haven't updated")
}
github.com/hashicorp/logutils
github.com/hashicorp/logutils
Levelsに指定した文字列、順序でLevelが登録される
Levels: []logutils.LogLevel{"DEBUG", "WARN", "ERROR"}
DEBUG, WARN, ERROR
WARN, DEBUG, ERROR
A, B, C
HOGE, FOO, BAR
与えた文字列の[ ]で括られた部分をレベルとして認識する
log.Print("[DEBUG] Debugging")
[DEBUG] FOO
FOOHOGE [DEBUG]
Hogehoge [DEBUG] FOO
LOGにレベル概念を付与し、
指定したレベル以上のログだけを出力させる機能
github.com/hashicorp/logutils
Levelsに指定した文字列、順序でLevelが登録される
Levels: []logutils.LogLevel{"DEBUG", "WARN", "ERROR"}
DEBUG, WARN, ERROR
WARN, DEBUG, ERROR
A, B, C
HOGE, FOO, BAR
与えた文字列の[ ]で括られた部分をレベルとして認識する
log.Print("[DEBUG] Debugging")
[DEBUG] FOO
FOOHOGE [DEBUG]
Hogehoge [DEBUG] FOO
LOGにレベル概念を付与し、
指定したレベル以上のログだけを出力させる機能
x := bytes.IndexByte(line, '[')
if x >= 0 {
y := bytes.IndexByte(line[x:], ']')
if y >= 0 {
level = LogLevel(line[x+1 : x+y])
}
}
_, ok := f.badLevels[level]
Kubernetesのロギング
golang/glog
staging/src/k8s.io/apiserver/pkg/util/logs
実態は、golang/glogを使用している。
k8s.io/apiserver/pkg/util/logs はglogの実装。
glogの既定のFlush時間を30秒から5秒に変更
func InitLogs() {
log.SetOutput(GlogWriter{})
log.SetFlags(0)
go wait.Until(glog.Flush, *logFlushFreq, wait.NeverStop)
}
Kubernetesのロギング
golang/glog
staging/src/k8s.io/apiserver/pkg/util/logs
実態は、golang/glogを使用している。
k8s.io/apiserver/pkg/util/logs はglogの実装。
google内で使用しているC++ロギングと同様のログ実装
Info、Warning、Error、Fatal関数の提供
Infofのような書式設定
Vスタイルのロギング
OpenShiftのロギング
k8s.io/apiserver/pkg/util/logs
github.com/kubernetes/apiserver/tree/master/pkg/util/logs
github.com/golang/glog
実態は、golang/glogを使用している。
Grafanaのロギング
オリジナル:grafana/grafana/pkg/log
github.com/grafana/grafana/pkg/log
inconshreveable/log15を使用している
var logLevels = map[string]log15.Lvl{
"trace": log15.LvlDebug,
"debug": log15.LvlDebug,
"info": log15.LvlInfo,
"warn": log15.LvlWarn,
"error": log15.LvlError,
"critical": log15.LvlCrit,
}
func Debug(format string, v ...interface{}) {
var message string
if len(v) > 0 {
message = fmt.Sprintf(format, v...)
} else {
message = format
}
Root.Debug(message)
}
Grafanaのロギング
inconshreveable/log15
github.com/grafana/grafana/pkg/log
inconshreveable/log15を使用している
key/value の構造型ログ
レベル付きログ
ターミナル出力時のカラーリング対応
ファイル、ストリーム、syslog、ネットワークへの出力
出力のバッファリング
Docker(moby/moby)のロギング
logrus
https://github.com/Sirupsen/logrus
if cli.Config.Experimental {
logrus.Warn("Running experimental build")
}
logrus.SetFormatter(&logrus.TextFormatter{
TimestampFormat: jsonmessage.RFC3339NanoFixed,
DisableColors: cli.Config.RawLogs,
FullTimestamp: true,
})
Docker(moby/moby)のロギング
logrus
https://github.com/Sirupsen/logrus
logrusは構造化Loggerです
レベル付きログ
コンソール出力時のカラー書式設定に対応
出力にJSON形式やテキスト形式、標準出力などに対応
InfluxDBのロギング
zap
github.com/uber-go/zap
func NewService(c Config) (*Service, error) {
s := Service{
checkInterval: time.Duration(c.CheckInterval),
advancePeriod: time.Duration(c.AdvancePeriod),
Logger: zap.New(zap.NullEncoder()),
}
return &s, nil
}
// WithLogger sets the logger for the service.
func (s *Service) WithLogger(log zap.Logger) {
s.Logger = log.With(zap.String("service", "shard-precreation"))
}
InfluxDBのロギング
zap
github.com/uber-go/zap
logrusは構造化Loggerです
レベル付きログ
glg https://github.com/kpango/glg glg is simple and fast leveled logging library for Go.
glog https://github.com/golang/glog Leveled execution logs for Go.
go-cronowriter https://github.com/utahta/go-cronowriter Simple writer that rotate log files automatically based on current date and time, like cronolog.
go-log https://github.com/siddontang/go-log Log lib supports level and multi handlers.
go-log https://github.com/ian-kent/go-log Log4j implementation in Go.
go-logger https://github.com/apsdehal/go-logger Simple logger of Go Programs, with level handlers.
gologger https://github.com/sadlil/gologger Simple easy to use log lib for go, logs in Colored Console, Simple Console, File or Elasticsearch.
gomol https://github.com/aphistic/gomol Multiple-output, structured logging for Go with extensible logging outputs.
gone/log https://github.com/One-com/gone/tree/master/log Fast, extendable, full-featured, std-lib source compatible log library.
log https://github.com/apex/log Structured logging package for Go.
log https://github.com/go-playground/log Simple, configurable and scalable Structured Logging for Go.
log-voyage https://github.com/firstrow/logvoyage Full-featured logging saas written in golang.
log15 https://github.com/inconshreveable/log15 Simple, powerful logging for Go.
logdump https://github.com/ewwwwwqm/logdump Package for multi-level logging.
logex https://github.com/chzyer/logex Golang log lib, supports tracking and level, wrap by standard log lib.
logger https://github.com/azer/logger Minimalistic logging library for Go.
logo https://github.com/mbndr/logo Golang logger to different configurable writers.
logrus https://github.com/Sirupsen/logrus Structured logger for Go.
logrusly https://github.com/sebest/logrusly logrus plug-in to send errors to a Loggly
logutils https://github.com/hashicorp/logutils Utilities for slightly better logging in Go (Golang) extending the standard logger.
logxi https://github.com/mgutz/logxi 12-factor app logger that is fast and makes you happy.
lumberjack https://github.com/natefinch/lumberjack Simple rolling logger, implements io.WriteCloser.
mlog https://github.com/jbrodriguez/mlog Simple logging module for go, with 5 levels, an optional rotating logfile feature and stdout/stderr output.
ozzo-log https://github.com/go-ozzo/ozzo-log
High performance logging supporting log severity, categorization, and filtering. Can send filtered log
messages to various targets (e.g. console, network, mail).
seelog https://github.com/cihub/seelog Logging functionality with flexible dispatching, filtering, and formatting.
slf https://github.com/ventu-io/slf The Structured Logging Facade (SLF) for Go (like SLF4J but structured and for Go).
slog https://github.com/ventu-io/slog The reference implementation of the Structured Logging Facade (SLF) for Go.
spew https://github.com/davecgh/go-spew Implements a deep pretty printer for Go data structures to aid in debugging.
stdlog https://github.com/alexcesaro/log Stdlog is an object-oriented library providing leveled logging. It is very useful for cron jobs.
tail https://github.com/hpcloud/tail Go package striving to emulate the features of the BSD tail program.
xlog https://github.com/xfxdev/xlog Plugin architecture and flexible log system for Go, with level ctrl, multiple log target and custom log format.
xlog https://github.com/rs/xlog Structured logger for `net/context` aware HTTP handlers with flexible dispatching.
参考:awesome-goのLoggingより34種類
Gocon2017:Goのロギング周りの考察
まとめ
ロギングは次の3パターンが多い
・fmt.Printf
・logパッケージから関数を使用する
・パッケージレベルのログ変数の宣言
ライブラリは乱立して、これが強いとかない状況
・Prometheus : go-kit/kit/log
・Hashicorp : hashicorp/logutils
・Docker : logrus
・kubernetes : golang/glog
・Grafana : inconshreveable/log15
まとめ
ライブラリは以下のような特徴を持つ傾向
key/value の構造型ログ
レベル付きログ
ターミナル出力時のカラーリング対応や書式設定
出力フォーマット
出力先
出力のバッファリング
目立った特徴を探すのが大変な状況。
自分の好みで良いかも?
ロギングライブラリ・ロギング実装に関する
お話でした
アプリケーションを書く際にロギング実装の検討材料になれば幸いです
Golang
http://sqlazure.jp/r/
コンタクト

More Related Content

Gocon2017:Goのロギング周りの考察