いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Goメモ-239 (bep/logg というログライブラリ使ってみた)

概要

bep/logg というログライブラリが公開されていて、ベンチマークの結果を見ると速かったのでちょっと触ってみました。

apex/log からフォークしたライブラリみたいですね。

まだ、バージョンは v0.1.0 だけど、シンプルな構成で使いやすいと思いました。

以下、サンプルです。せっかくなので、ちょっと非同期処理しながらログ出力するようにしてみました。

サンプル

package main

import (
    "context"
    "fmt"
    "io"
    "net/http"
    "os"
    "runtime"

    "github.com/bep/logg"
    "github.com/bep/logg/handlers/cli"
    "github.com/devlights/gomy/chans"
    "github.com/devlights/gomy/errs"
)

type (
    data struct {
        url    string
        length int
        info   *logg.Entry
    }
)

var (
    handler = cli.New(os.Stderr)
    logger  = logg.New(logg.Options{Level: logg.LevelInfo, Handler: handler})
    appLog  = logger.WithLevel(logg.LevelInfo)
)

func main() {
    var (
        ctx  = context.Background()
        done = ctx.Done()
        urls = []string{
            "https://devlights.hatenablog.com/",
            "https://github.com/devlights/gomy",
            "https://github.com/devlights/try-golang",
            "https://github.com/devlights/try-python",
            "https://github.com/devlights/try-csharp",
            "https://qiita.com/",
            "https://zenn.dev/",
            "https://dev.to/",
        }
    )

    var (
        in  = chans.ForEach(done, urls...)
        out = make(chan data)
    )

    var (
        workerCount = runtime.NumCPU() / 2
        fanOut      = chans.FanOut(done, in, workerCount, func(url string) {
            info := appLog.WithField("url", url)

            info.Log(logg.String("fetching"))
            defer info.Log(logg.String("fetched "))

            resp := errs.Panic(http.Get(url))
            defer resp.Body.Close()

            buf := errs.Panic(io.ReadAll(resp.Body))
            out <- data{url, len(buf), info}
        })
    )

    go func() {
        defer close(out)
        <-chans.WhenAll(fanOut...)
    }()

    for v := range out {
        v := v
        v.info.Log(logg.StringFunc(func() string {
            return fmt.Sprintf("%d bytes", v.length)
        }))
    }
}

実行すると、例えば以下のように出力されます。

$ go run main.go
   • fetching                  url=https://devlights.hatenablog.com/
   • fetching                  url=https://qiita.com/
   • fetching                  url=https://github.com/devlights/try-python
   • fetching                  url=https://github.com/devlights/gomy
   • fetching                  url=https://github.com/devlights/try-golang
   • fetching                  url=https://zenn.dev/
   • fetching                  url=https://github.com/devlights/try-csharp
   • fetched                   url=https://github.com/devlights/gomy
   • 216923 bytes              url=https://github.com/devlights/gomy
   • fetched                   url=https://github.com/devlights/try-csharp
   • 191365 bytes              url=https://github.com/devlights/try-csharp
   • fetched                   url=https://github.com/devlights/try-golang
   • 208036 bytes              url=https://github.com/devlights/try-golang
   • fetched                   url=https://github.com/devlights/try-python
   • 200681 bytes              url=https://github.com/devlights/try-python
   • fetched                   url=https://zenn.dev/
   • fetching                  url=https://dev.to/
   • 164268 bytes              url=https://zenn.dev/
   • fetched                   url=https://dev.to/
   • 479801 bytes              url=https://dev.to/
   • fetched                   url=https://devlights.hatenablog.com/
   • 64004 bytes               url=https://devlights.hatenablog.com/
   • fetched                   url=https://qiita.com/
   • 183852 bytes              url=https://qiita.com/

上の出力は、ハンドラを cli にしている状態で、 text にすると以下のようになります。

$ go run main.go
INFO fetching url=https://devlights.hatenablog.com/
INFO fetching url=https://github.com/devlights/try-csharp
INFO fetching url=https://github.com/devlights/try-golang
INFO fetching url=https://github.com/devlights/try-python
INFO fetching url=https://zenn.dev/
INFO fetching url=https://dev.to/
INFO fetching url=https://qiita.com/
INFO fetched  url=https://zenn.dev/
INFO 164268 bytes url=https://zenn.dev/
INFO fetched  url=https://dev.to/
INFO 479801 bytes url=https://dev.to/
INFO fetched  url=https://github.com/devlights/try-python
INFO 200681 bytes url=https://github.com/devlights/try-python
INFO fetched  url=https://devlights.hatenablog.com/
INFO fetching url=https://github.com/devlights/gomy
INFO 64004 bytes url=https://devlights.hatenablog.com/
INFO fetched  url=https://github.com/devlights/try-csharp
INFO 191365 bytes url=https://github.com/devlights/try-csharp
INFO fetched  url=https://github.com/devlights/try-golang
INFO 208036 bytes url=https://github.com/devlights/try-golang
INFO fetched  url=https://qiita.com/
INFO 183852 bytes url=https://qiita.com/
INFO fetched  url=https://github.com/devlights/gomy
INFO 226120 bytes url=https://github.com/devlights/gomy

jsonにすると以下のようになります。

$ go run main.go
{"level":"info","timestamp":"2022-08-12T06:48:49.052414898Z","fields":[{"name":"url","value":"https://github.com/devlights/try-golang"}],"message":"fetching"}
{"level":"info","timestamp":"2022-08-12T06:48:49.052455998Z","fields":[{"name":"url","value":"https://github.com/devlights/try-csharp"}],"message":"fetching"}
{"level":"info","timestamp":"2022-08-12T06:48:49.052478928Z","fields":[{"name":"url","value":"https://github.com/devlights/try-python"}],"message":"fetching"}
{"level":"info","timestamp":"2022-08-12T06:48:49.052485748Z","fields":[{"name":"url","value":"https://devlights.hatenablog.com/"}],"message":"fetching"}
{"level":"info","timestamp":"2022-08-12T06:48:49.052493508Z","fields":[{"name":"url","value":"https://github.com/devlights/gomy"}],"message":"fetching"}
{"level":"info","timestamp":"2022-08-12T06:48:49.124647118Z","fields":[{"name":"url","value":"https://github.com/devlights/try-python"}],"message":"fetched "}
{"level":"info","timestamp":"2022-08-12T06:48:49.124701448Z","fields":[{"name":"url","value":"https://github.com/devlights/try-python"}],"message":"200681 bytes"}
{"level":"info","timestamp":"2022-08-12T06:48:49.127061278Z","fields":[{"name":"url","value":"https://github.com/devlights/try-csharp"}],"message":"191365 bytes"}
{"level":"info","timestamp":"2022-08-12T06:48:49.127022028Z","fields":[{"name":"url","value":"https://github.com/devlights/try-csharp"}],"message":"fetched "}
{"level":"info","timestamp":"2022-08-12T06:48:49.127183268Z","fields":[{"name":"url","value":"https://qiita.com/"}],"message":"fetching"}
{"level":"info","timestamp":"2022-08-12T06:48:49.131769767Z","fields":[{"name":"url","value":"https://github.com/devlights/gomy"}],"message":"fetched "}
{"level":"info","timestamp":"2022-08-12T06:48:49.131796387Z","fields":[{"name":"url","value":"https://dev.to/"}],"message":"fetching"}
{"level":"info","timestamp":"2022-08-12T06:48:49.131890257Z","fields":[{"name":"url","value":"https://github.com/devlights/gomy"}],"message":"214604 bytes"}
{"level":"info","timestamp":"2022-08-12T06:48:49.133329867Z","fields":[{"name":"url","value":"https://github.com/devlights/try-golang"}],"message":"fetched "}
{"level":"info","timestamp":"2022-08-12T06:48:49.133365087Z","fields":[{"name":"url","value":"https://github.com/devlights/try-golang"}],"message":"208036 bytes"}
{"level":"info","timestamp":"2022-08-12T06:48:49.1765476Z","fields":[{"name":"url","value":"https://dev.to/"}],"message":"fetched "}
{"level":"info","timestamp":"2022-08-12T06:48:49.17662295Z","fields":[{"name":"url","value":"https://dev.to/"}],"message":"479801 bytes"}
{"level":"info","timestamp":"2022-08-12T06:48:49.426874904Z","fields":[{"name":"url","value":"https://devlights.hatenablog.com/"}],"message":"fetched "}
{"level":"info","timestamp":"2022-08-12T06:48:49.426951764Z","fields":[{"name":"url","value":"https://zenn.dev/"}],"message":"fetching"}
{"level":"info","timestamp":"2022-08-12T06:48:49.426990114Z","fields":[{"name":"url","value":"https://devlights.hatenablog.com/"}],"message":"64004 bytes"}
{"level":"info","timestamp":"2022-08-12T06:48:49.442471392Z","fields":[{"name":"url","value":"https://zenn.dev/"}],"message":"fetched "}
{"level":"info","timestamp":"2022-08-12T06:48:49.442509422Z","fields":[{"name":"url","value":"https://zenn.dev/"}],"message":"164268 bytes"}
{"level":"info","timestamp":"2022-08-12T06:48:49.805860549Z","fields":[{"name":"url","value":"https://qiita.com/"}],"message":"183852 bytes"}
{"level":"info","timestamp":"2022-08-12T06:48:49.805652549Z","fields":[{"name":"url","value":"https://qiita.com/"}],"message":"fetched "}

参考情報

github.com

Go言語による並行処理

Go言語による並行処理

Amazon


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。