はじめに
GWは時間を持て余していたので、前々から作りたかった
go lang向けのloggerを作ってみました。
Simpleな機能だけで終わらせたかったのですが、不思議と作り込んでしまい
GWの時間をほぼ捧げてしまいました(血涙
Slogger(SimpleLogger)
今回作ったloggerの名前です。
Thread-safeで、以下の機能を有しています!
- LogLevel
- Logを記録した回数(LogLevel毎に取得可能)
- Logを記録した日付に合わせたFile出力
- 非同期記録
- Formatの調整は無く、Processorの実装で独自の出力対応
Processorについては後述します。(LTSVで標準出力してみます)
使ってみる!
Install
go get github.com/flowtumn/slogger
Demo
package main
import (
"github.com/flowtumn/slogger"
)
func main() {
logger, err := slogger.CreateSlogger(
slogger.SloggerSettings{
LogLevel: slogger.DEBUG, // DEBUG以上は全て記録。
LogName: "EXAMPLE-SLOGGER", // Loggerの名前。この名前でFile保存される。
LogDirectory: "/tmp", // Log保存先のDirectory。
LogExtension: "log", // Logの拡張子。
},
slogger.CreateSloggerProcessorFile(), //Logを処理するProcessor。Fileに記録する。
)
if nil != err {
panic(err)
}
defer func() {
//Closeを呼びlogをflush
logger.Close()
}()
logger.Debug("Debug Message. %+v", map[int]int{100: 200, 300: 400, 500: 600})
logger.Info("Info Message.")
logger.Warn("Warn Message.")
logger.Error("Error Message.")
logger.Critical("Critical Message.")
//記録した回数を表示。
fmt.Printf("%+v\n", logger.RecordCounter());
}
結果
$ go run main.go
&{Debug:1 Info:1 Warn:1 Error:1 Critical:1}
$ cat /tmp/EXAMPLE-SLOGGER-2017-05-06.log
2017-05-06 23:41:46 [DEBUG] main.go(22): Debug Message. map[100:200 300:400 500:600]
2017-05-06 23:41:46 [INFO] main.go(23): Info Message.
2017-05-06 23:41:46 [WARN] main.go(24): Warn Message.
2017-05-06 23:41:46 [ERROR] main.go(25): Error Message.
2017-05-06 23:41:46 [CRITICAL] main.go(26): Critical Message.
イメージ通りの出力になっていますでしょうか。
普通に使う上では、slogger.SloggerSettingsを適宜設定すればお使い頂けると思います。
slogger.CreateSloggerProcessorFile()
はFileに記録するProcessorになっており
一般的な使い方ならslogger.CreateSloggerProcessorFile()
を指定して下さい。
Processorを作ってLTSV出力
折角GW中に作ったので、Processorを独自に実装し、LTSV出力をしてみます。
loggerを普通に使いたい方にはあまり有用な情報ではありません(。。
Interface
まず以下を実装する必要があります。
type SloggerProcessor interface {
// LoggerがRecordに成功した時に呼ばれます。Logger本体もGetLogPathを持っており、ここで受け取った値を返しています。
GetLogPath() *string
// Loggerが記録する時 thread-safe に呼ばれます。(errorを返すと、失敗と見なし記録した回数を更新しません)
Record(SloggerSettings, *SloggerData) error
// Loggerが停止する時に呼ばれます。
Shutdown()
}
LTSV Processorの実装
さて実装してみましょう。お題はLTSV出力。
Recordの中で、tabを挟んで標準出力しています。
type ExampleProcessorLTSV struct {
}
func (self *ExampleProcessorLTSV) GetLogPath() *string {
//標準出力なので、Pathというものは無し。
return nil
}
func (self *ExampleProcessorLTSV) Record(setting slogger.SloggerSettings, data *slogger.SloggerData) error {
/////
//settingは、初回のCreateSloggerで渡したSloggerSettingsがそのまま渡されます。
/////
//slogger.SloggerDataには以下の情報を持っています。
// LogLevel
// 記録した時間(ms)
// 呼んだソースコード名
// 呼んだ行番号
// 実際に記録したLogMessage
/////
fmt.Printf("%s\t%s\t%d\t%s\t%s\n",
data.LogLevel.ToString(),
data.SourceName,
data.SourceLine,
slogger.ConvertTimeStamp(data.CurrentTimeMillis, slogger.Full),
data.LogMessage,
)
return nil
}
func (self *ExampleProcessorLTSV) Shutdown() {
//標準出力なので後始末は不要
}
//LTSVProcessorのInstanceを返します。
func CreateProcessorLTSV() *slogger.SloggerProcessor {
var r slogger.SloggerProcessor
r = &ExampleProcessorLTSV{}
return &r
}
以上で完成になります!
実装コードの中の CreateProcessorLTSV ですが、私自身この書き方に違和感があります。
もっと簡単且つ適当なやり方がありましたら、是非ご教授願いたいです。
LTSV Processorを実行。
動作させてみましょう! slogger.CreateSloggerに渡すProcessorを
今回作ったLTSVに置き換えるだけになります。
package main
import (
"fmt"
"github.com/flowtumn/slogger"
)
func main() {
logger, err := slogger.CreateSlogger(
slogger.SloggerSettings{
LogLevel: slogger.DEBUG,
LogName: "EXAMPLE-SLOGGER",
LogDirectory: "/tmp",
LogExtension: "log",
},
CreateProcessorLTSV(), //Processorを LTSV に変更。
)
if nil != err {
panic(err)
}
defer func() {
//Closeを呼びlogをflush
logger.Close()
}()
logger.Debug("Debug Message. %+v", map[int]int{100: 200, 300: 400, 500: 600})
logger.Info("Info Message.")
logger.Warn("Warn Message.")
logger.Error("Error Message.")
logger.Critical("Critical Message.")
//記録した回数を表示。
fmt.Printf("%+v\n", logger.RecordCounter());
}
結果
go run main.go
[DEBUG] main.go 56 2017-05-07 13:35:14 Debug Message. map[100:200 300:400 500:600]
[INFO] main.go 57 2017-05-07 13:35:14 Info Message.
[WARN] main.go 58 2017-05-07 13:35:14 Warn Message.
[ERROR] main.go 59 2017-05-07 13:35:14 Error Message.
[CRITICAL] main.go 60 2017-05-07 13:35:14 Critical Message.
&{Debug:1 Info:1 Warn:1 Error:1 Critical:1}
きちんとLTSVで出力されていますね!!
今回は標準出力にしていますが、鋭い方は File に記録する時はどうするの?とお察しのはず。
ご明察の通り、現状は Format を変えての File 記録には、Fileに書き落とす処理も自分で書く必要があります(><
今後の課題とさせて下さい。
CacheProcessorとか、これから追加したいなーと考えています。
2017/9/17 ProcessorCacheFileを追加しました。
その他
2017/9/17 出力方式にCacheFileを追加し、BenchMarkもGraphにしてみました。
BentchMarkの対象は
NullSink(/dev/null相当)
CacheFile(Non-Blocking)
File(Blocking)
となり、Githubのページで見ることが出来ます。
Github