いろいろ備忘録日記

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

Goメモ-485 (slogメモ-08)(グループ (1))

関連記事

Goメモ-477 (slogメモ-01)(基本的な使い方) - いろいろ備忘録日記

Goメモ-478 (slogメモ-02)(構造化ログの出力) - いろいろ備忘録日記

Goメモ-479 (slogメモ-03)(デフォルトロガー) - いろいろ備忘録日記

Goメモ-480 (slogメモ-04)(従来のlogパッケージとの連携) - いろいろ備忘録日記

Goメモ-482 (slogメモ-05)(テキスト形式のログ) - いろいろ備忘録日記

Goメモ-483 (slogメモ-06)(JSON形式のログ) - いろいろ備忘録日記

Nushellメモ-03 (外部コマンドの結果をリダイレクト) - いろいろ備忘録日記

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。

今更ながら、Go 1.21で導入された log/slog を使ってみたりしています。

少しづつメモしていきます。今回はグループ について。

サンプル

main.go

package main

import (
    "context"
    "fmt"
    "log/slog"
    "os"
    "strings"
)

func main() {
    var (
        rootCtx  = context.Background()
        ctx, cxl = context.WithCancel(rootCtx)
    )
    defer cxl()

    if err := run(ctx); err != nil {
        slog.Error("ERROR", "err", err)
        os.Exit(1)
    }
}

func run(_ context.Context) error {
    //
    // slogパッケージにおけるグループの概念は、関連する属性をまとめて階層構造を作成するための強力な機能である。
    // グループを使用することで、ログの可読性が向上し、構造化されたデータの管理が容易になる。
    //
    // グループの利点は以下の通り
    //   - 構造化: 関連する情報を論理的にグループ化出来る
    //   - 可読性: ログの階層構造が明確になり、情報の関連性が理解しやすくなる
    //   - フィルタリング: グループ名を使用して特定の情報を容易に抽出できる
    //
    // 特に JSON 形式で構造化ログとして出力した場合に扱いやすい。
    //
    // 基本的に利用するのは
    //   - slog.With()
    //   - slog.WithGroup()
    //   - slog.Group() と {slog.Int(), slog.String(), slog.Time() など}
    // となる。
    //
    // グループを付与すると、HandlerOptions.ReplaceAttr()の第一引数 groups に
    // そのキーが所属するグループ情報が設定される。
    //

    var (
        level = &slog.LevelVar{}
        opt   = &slog.HandlerOptions{
            Level:       level,
            ReplaceAttr: composite(showGroup, noTimeKey),
        }
        handler    = slog.NewTextHandler(os.Stdout, opt)
        rootLogger = slog.New(handler)
        logger     = rootLogger.With()
    )

    // グループ無し
    logger.Info("INFO message", "key", "value")

    // グループ有り
    logger = rootLogger.WithGroup("group1")
    logger.Info("INFO message", "key", "value")

    // サブグループ付き
    logger = rootLogger.WithGroup("group1")
    logger = logger.WithGroup("group2")
    logger.Info("INFO message", "key", "value")

    return nil
}

func noTimeKey(groups []string, a slog.Attr) slog.Attr {
    if a.Key == slog.TimeKey {
        return slog.Attr{}
    }

    return a
}

func showGroup(groups []string, a slog.Attr) slog.Attr {
    if len(groups) != 0 {
        fmt.Printf("group=[%s]\n", strings.Join(groups, ","))
    }

    return a
}

func composite(fns ...func([]string, slog.Attr) slog.Attr) func([]string, slog.Attr) slog.Attr {
    return func(groups []string, a slog.Attr) slog.Attr {
        var lastReturn slog.Attr
        for _, fn := range fns {
            lastReturn = fn(groups, a)
        }

        return lastReturn
    }
}

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

Taskfile.yml

# https://taskfile.dev

version: '3'

tasks:
  default:
    cmds:
      - task: run
  run:
    cmds:
      - go run main.go

shell

$ task
task: [run] go run main.go
level=INFO msg="INFO message" key=value
group=[group1]
level=INFO msg="INFO message" group1.key=value
group=[group1,group2]
level=INFO msg="INFO message" group1.group2.key=value

try-golang/examples/slog at main · devlights/try-golang · GitHub

参考情報

Goのおすすめ書籍


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

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