Help us understand the problem. What is going on with this article?

go langのSimpleなloggerを作った話

More than 1 year has passed since last update.

はじめに

 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

main.go
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

まず以下を実装する必要があります。

interface.go
type SloggerProcessor interface {
    // LoggerがRecordに成功した時に呼ばれます。Logger本体もGetLogPathを持っており、ここで受け取った値を返しています。
    GetLogPath() *string

    // Loggerが記録する時 thread-safe に呼ばれます。(errorを返すと、失敗と見なし記録した回数を更新しません)
    Record(SloggerSettings, *SloggerData) error

    // Loggerが停止する時に呼ばれます。
    Shutdown()
}

LTSV Processorの実装

さて実装してみましょう。お題はLTSV出力。
Recordの中で、tabを挟んで標準出力しています。

ltsv_processor.go
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に置き換えるだけになります。

main.go
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

https://github.com/flowtumn/slogger

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした