2019年9月1日日曜日

go-workers でカスタムログを設定する方法

概要

Sidekiq と互換性のある golang 製の go-workers でカスタムロギングを設定する方法を紹介します

環境

  • macOS 10.14.6
  • go 1.12.9

通常の場合

package main

import (
    "github.com/jrallison/go-workers"
    "time"
)

func perform(msg *workers.Msg) {
    c, _ := msg.Args().Int()
    for i := 0; i < c; i++ {
        time.Sleep(1 * time.Second)
        workers.Logger.Println(i)
    }
    workers.Logger.Println("end")
}

func main() {
    workers.Configure(map[string]string{
        "server":  "localhost:6379",
        "process": "1",
    })
    workers.Process("default", perform, 1)
    workers.Run()
}

これで実行すると以下のようなフォーマットで表示されます

workers: 2019/08/30 15:35:04.775722 processing queue default with 1 workers. workers: 2019/08/30 15:35:08.105867 default JID-e00935689dcbdb78123b2ad8 start workers: 2019/08/30 15:35:08.105963 default JID-e00935689dcbdb78123b2ad8 args: 5 workers: 2019/08/30 15:35:09.109906 0 workers: 2019/08/30 15:35:10.113329 1 workers: 2019/08/30 15:35:11.117978 2 workers: 2019/08/30 15:35:12.119421 3 workers: 2019/08/30 15:35:13.124138 4 workers: 2019/08/30 15:35:13.124182 end workers: 2019/08/30 15:35:13.124655 default JID-e00935689dcbdb78123b2ad8 done: 5.01861994s

これをいろいろとカスタムしてみたいと思います

そもそもカスタムするには

公式の issue に回答があります
基本的には workers.Logger に好きな logger を設定すれば OK です
それ以外にも PrintlnPrintf を実装した構造体を設定しても OK です
後者のほうがより自分でカスタマイズできます

特定の値を常に入れる

例えばファイル名と実行行数を入れたい場合には以下のようにします

package main

import (
    "github.com/jrallison/go-workers"
    "log"
    "os"
    "time"
)

func perform(msg *workers.Msg) {
    c, _ := msg.Args().Int()
    for i := 0; i < c; i++ {
        time.Sleep(1 * time.Second)
        workers.Logger.Println(i)
    }
    workers.Logger.Println("end")
}

func main() {
    logger := log.New(os.Stdout, "workers: ", log.Ldate|log.Lmicroseconds)
    logger.SetFlags(log.LstdFlags | log.Lshortfile)
    workers.Logger = logger
    workers.Configure(map[string]string{
        "server":  "localhost:6379",
        "process": "1",
    })
    workers.Process("default", perform, 1)
    workers.Run()
}

=> workers: 2019/08/30 16:22:49 manager.go:53: processing queue default with 1 workers.

標準の log パッケージを使って logger を作成し SetFlags でファイル名と行数を出力するようにしています
こんな感じで好きなロギングパッケージを workers.Logger に設定することでカスタムできます

Println と Printf を実装する

もうひとつの方法を紹介します
こちらのほうがカスタマイズ性は高いですが考慮することが多いので面倒でもあります
構造体を一つ定義しそこに PrintlnPrintf 関数を実装します

package main

import (
    "encoding/json"
    "fmt"
    "github.com/jrallison/go-workers"
    "strconv"
    "sync"
    "time"
)

type MyLogger struct {
}

func (l *MyLogger) Println(v ...interface{}) {
    m := map[string]string{}
    for i, vv := range v {
        switch vv.(type) {
        case string:
            m["msg"+strconv.Itoa(i)] = vv.(string)
        case int:
            m["msg"+strconv.Itoa(i)] = strconv.Itoa((vv.(int)))
        }
    }
    j, _ := json.Marshal(m)
    fmt.Println(string(j))
}
func (l *MyLogger) Printf(fmt string, v ...interface{}) {
    // noop
}

func waiter(i int) {
    t := time.Duration(i)
    time.Sleep(t * time.Second)
    workers.Logger.Println(i)
}

func perform(msg *workers.Msg) {
    c, _ := msg.Args().Int()
    var wg sync.WaitGroup
    for i := 0; i < c; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            waiter(i)
        }(i)
    }
    wg.Wait()
    workers.Logger.Println("end")
}

func main() {
    workers.Logger = &MyLogger{}
    workers.Configure(map[string]string{
        "server":  "localhost:6379",
        "process": "1",
    })
    workers.Process("default", perform, 1)
    workers.Run()
}

=> {"msg0":"processing queue","msg1":"default","msg2":"with","msg3":"1","msg4":"workers."}

[]interface{} で渡ってくるので型を意識する必要があります
今回は JSON に変換していますがそれが目的であればサードパーティのパッケージを使ったほうが良いかなと思います
また上記では Println 関数しか実装していませんが Printf も使うのであれば実装しましょう

最後に

go-workers でロギングをカスタマイズする方法を紹介しました
個人的には workers.Logger をロギングパッケージで上書きする方法が簡単で良いかなと思います
自分でロガーを作成したい場合は後者の Println を実装する方法をおすすめします

参考サイト

0 件のコメント:

コメントを投稿