log/slog (Standard Library)

Go 1.21で導入された標準ライブラリの構造化ロギング機能。外部依存関係なしでプロダクション対応の高性能ログ機能を提供。機能とシンプルさの優れたバランスにより、新規プロジェクトでの推奨選択肢。

ロギングライブラリGo標準ライブラリ構造化ログ高性能Go 1.21

GitHub概要

golang/go

The Go programming language

ホームページ:https://go.dev
スター130,461
ウォッチ3,357
フォーク18,395
作成日:2014年8月19日
言語:Go
ライセンス:BSD 3-Clause "New" or "Revised" License

トピックス

gogolanglanguageprogramming-language

スター履歴

golang/go Star History
データ取得日時: 2025/10/22 10:20

ライブラリ

log/slog (Standard Library)

概要

log/slogは、Go 1.21で導入された標準ライブラリの構造化ロギング機能です。外部依存関係なしでプロダクション対応の高性能ログ機能を提供し、機能とシンプルさの優れたバランスにより、新規プロジェクトでの推奨選択肢となっています。2025年現在、Go 1.21以降の新規プロジェクトでの第一選択肢として急速に定着し、標準ライブラリのため長期サポートが保証されています。

詳細

log/slogは2025年においてGo開発の新しいスタンダードとして確固たる地位を築いています。Go 1.21の最重要機能として導入され、従来のlog2、logrusなどのサードパーティライブラリの機能を標準ライブラリに統合しました。構造化ログをネイティブサポートし、JSON、テキスト、カスタムフォーマットに対応。レベルベースロギング、コンテキスト情報の保持、高いパフォーマンスを実現しながら、標準ライブラリならではのシンプルさと信頼性を提供します。

主な特徴

  • 標準ライブラリ統合: 外部依存なしで完全な構造化ログ機能
  • 高性能設計: ゼロアロケーション最適化とパフォーマンス重視
  • 柔軟なハンドラー: JSON、テキスト、カスタムハンドラー対応
  • レベルベースログ: Debug、Info、Warn、Errorの4段階レベル
  • コンテキスト対応: context.Contextとの完全統合
  • アトリビュート管理: 構造化データの効率的な管理
  • 設定可能性: ログレベル、出力先、フォーマットの柔軟な設定

メリット・デメリット

メリット

  • Go標準ライブラリとしての長期安定性と互換性保証
  • 外部依存関係なしでの完全な構造化ログ機能
  • 高いパフォーマンスとメモリ効率性の実現
  • 一貫したAPIとGo慣例に準拠した設計
  • JSON、テキスト形式での豊富な出力オプション
  • context.Contextとの自然な統合によるリクエストトレーシング

デメリット

  • Go 1.21以降が必要で古いGoバージョンでは利用不可
  • サードパーティライブラリ(logrus、zap等)ほど豊富な機能なし
  • ログローテーションやファイル管理機能の不足
  • 高度なフィルタリングや変換機能の限定性
  • 既存プロジェクトでの移行コストと学習曲線
  • エコシステム統合での一部制限(既存ライブラリとの互換性)

参考ページ

書き方の例

基本的なセットアップとログ出力

package main

import (
    "context"
    "log/slog"
    "os"
    "time"
)

func main() {
    // デフォルトのTextHandlerでロガー設定
    logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
    slog.SetDefault(logger)
    
    // 基本的なログレベル使用
    slog.Debug("デバッグメッセージ") // デフォルトでは出力されない
    slog.Info("アプリケーション開始")
    slog.Warn("設定ファイルが見つかりません")
    slog.Error("データベース接続エラー")
    
    // 構造化ログ(キー・バリューペア)
    slog.Info("ユーザーログイン",
        "user_id", 12345,
        "username", "[email protected]",
        "ip_address", "192.168.1.100",
        "timestamp", time.Now(),
    )
    
    // slog.Attrを使用した構造化ログ
    slog.Info("HTTPリクエスト",
        slog.String("method", "GET"),
        slog.String("path", "/api/users"),
        slog.Int("status_code", 200),
        slog.Duration("response_time", 150*time.Millisecond),
        slog.Bool("cached", true),
    )
    
    // Groupによる構造化
    slog.Info("データベース操作",
        slog.Group("database",
            slog.String("operation", "SELECT"),
            slog.String("table", "users"),
            slog.Int("rows_affected", 25),
        ),
        slog.Group("performance",
            slog.Duration("query_time", 45*time.Millisecond),
            slog.Int64("memory_used", 1024*1024),
        ),
    )
}

JSONハンドラーとログレベル設定

package main

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

func main() {
    // JSONハンドラーでの設定
    jsonHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
        Level: slog.LevelDebug, // デバッグレベルから出力
        AddSource: true,        // ソースコード位置を含める
        ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
            // タイムスタンプのフォーマットをカスタマイズ
            if a.Key == slog.TimeKey {
                return slog.String("timestamp", a.Value.Time().Format("2006-01-02 15:04:05"))
            }
            return a
        },
    })
    
    logger := slog.New(jsonHandler)
    slog.SetDefault(logger)
    
    // デバッグログが出力される
    slog.Debug("詳細デバッグ情報",
        "function", "processData",
        "variables", map[string]any{
            "counter": 42,
            "enabled": true,
            "config": []string{"option1", "option2"},
        },
    )
    
    // エラーログと詳細情報
    err := performOperation()
    if err != nil {
        slog.Error("操作失敗",
            "error", err,
            "operation", "data_processing",
            slog.Group("context",
                slog.String("module", "data_processor"),
                slog.String("version", "1.2.3"),
                slog.Int("retry_count", 3),
            ),
        )
    }
    
    // 成功時のログ
    slog.Info("処理成功",
        "result", "データ処理完了",
        "processed_items", 150,
        slog.Group("metrics",
            slog.Float64("success_rate", 98.5),
            slog.Int("errors", 2),
            slog.Int("warnings", 5),
        ),
    )
}

func performOperation() error {
    // 何らかの処理とエラーシミュレーション
    return nil // または errors.New("処理エラー")
}

コンテキスト統合とリクエストトレーシング

package main

import (
    "context"
    "fmt"
    "log/slog"
    "net/http"
    "os"
    "time"
    "crypto/rand"
    "encoding/hex"
)

// リクエストIDを生成する関数
func generateRequestID() string {
    bytes := make([]byte, 16)
    rand.Read(bytes)
    return hex.EncodeToString(bytes)
}

// コンテキストキー
type contextKey string

const (
    requestIDKey contextKey = "request_id"
    userIDKey    contextKey = "user_id"
)

// ミドルウェア:リクエストIDとログ設定
func loggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        requestID := generateRequestID()
        
        // コンテキストにリクエストIDを追加
        ctx := context.WithValue(r.Context(), requestIDKey, requestID)
        r = r.WithContext(ctx)
        
        // リクエスト開始ログ
        slog.InfoContext(ctx, "リクエスト開始",
            "request_id", requestID,
            "method", r.Method,
            "path", r.URL.Path,
            "remote_addr", r.RemoteAddr,
            "user_agent", r.UserAgent(),
        )
        
        start := time.Now()
        
        // 次のハンドラーを実行
        next.ServeHTTP(w, r)
        
        // リクエスト完了ログ
        duration := time.Since(start)
        slog.InfoContext(ctx, "リクエスト完了",
            "request_id", requestID,
            "duration", duration,
            "status", "completed",
        )
    }
}

// APIハンドラー例
func getUserHandler(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()
    
    // ユーザーIDをパスから取得(簡単な例)
    userID := r.URL.Path[len("/api/users/"):]
    
    // コンテキストにユーザーIDを追加
    ctx = context.WithValue(ctx, userIDKey, userID)
    
    slog.InfoContext(ctx, "ユーザー情報取得開始",
        "user_id", userID,
        "operation", "get_user",
    )
    
    // データベースからユーザー情報を取得(シミュレーション)
    user, err := fetchUserFromDB(ctx, userID)
    if err != nil {
        slog.ErrorContext(ctx, "ユーザー取得エラー",
            "user_id", userID,
            "error", err,
            slog.Group("database",
                slog.String("operation", "SELECT"),
                slog.String("table", "users"),
            ),
        )
        http.Error(w, "Internal Server Error", http.StatusInternalServerError)
        return
    }
    
    slog.InfoContext(ctx, "ユーザー情報取得成功",
        "user_id", userID,
        "username", user.Username,
        slog.Group("user_details",
            slog.String("email", user.Email),
            slog.Time("last_login", user.LastLogin),
            slog.Bool("active", user.Active),
        ),
    )
    
    // レスポンス送信
    w.Header().Set("Content-Type", "application/json")
    fmt.Fprintf(w, `{"id":"%s","username":"%s","email":"%s"}`, 
        user.ID, user.Username, user.Email)
}

// ユーザー構造体
type User struct {
    ID        string
    Username  string
    Email     string
    LastLogin time.Time
    Active    bool
}

// データベースからユーザーを取得(シミュレーション)
func fetchUserFromDB(ctx context.Context, userID string) (*User, error) {
    slog.DebugContext(ctx, "データベースクエリ実行",
        "query", "SELECT * FROM users WHERE id = ?",
        "params", []string{userID},
    )
    
    // データベース処理のシミュレーション
    time.Sleep(50 * time.Millisecond)
    
    if userID == "error" {
        return nil, fmt.Errorf("ユーザーが見つかりません")
    }
    
    return &User{
        ID:        userID,
        Username:  fmt.Sprintf("user_%s", userID),
        Email:     fmt.Sprintf("user_%[email protected]", userID),
        LastLogin: time.Now().Add(-24 * time.Hour),
        Active:    true,
    }, nil
}

func main() {
    // JSON形式でログ出力を設定
    jsonHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
        Level: slog.LevelDebug,
        AddSource: false,
    })
    slog.SetDefault(slog.New(jsonHandler))
    
    // HTTPサーバーのセットアップ
    http.HandleFunc("/api/users/", loggingMiddleware(getUserHandler))
    
    slog.Info("HTTPサーバー開始",
        "port", 8080,
        "handlers", []string{"/api/users/"},
    )
    
    // サーバー起動
    if err := http.ListenAndServe(":8080", nil); err != nil {
        slog.Error("サーバー起動エラー",
            "error", err,
            "port", 8080,
        )
    }
}

カスタムハンドラーと高度な使用例

package main

import (
    "context"
    "fmt"
    "io"
    "log/slog"
    "os"
    "strings"
    "sync"
    "time"
)

// カスタムハンドラー:ログをメモリにバッファリング
type BufferedHandler struct {
    mu      sync.Mutex
    buffer  []LogEntry
    maxSize int
    handler slog.Handler
}

type LogEntry struct {
    Time    time.Time
    Level   slog.Level
    Message string
    Attrs   []slog.Attr
}

func NewBufferedHandler(maxSize int, underlying slog.Handler) *BufferedHandler {
    return &BufferedHandler{
        buffer:  make([]LogEntry, 0, maxSize),
        maxSize: maxSize,
        handler: underlying,
    }
}

func (h *BufferedHandler) Enabled(ctx context.Context, level slog.Level) bool {
    return h.handler.Enabled(ctx, level)
}

func (h *BufferedHandler) Handle(ctx context.Context, r slog.Record) error {
    h.mu.Lock()
    defer h.mu.Unlock()
    
    // エントリをバッファに追加
    entry := LogEntry{
        Time:    r.Time,
        Level:   r.Level,
        Message: r.Message,
        Attrs:   make([]slog.Attr, 0),
    }
    
    r.Attrs(func(a slog.Attr) bool {
        entry.Attrs = append(entry.Attrs, a)
        return true
    })
    
    h.buffer = append(h.buffer, entry)
    
    // バッファサイズの制限
    if len(h.buffer) > h.maxSize {
        h.buffer = h.buffer[1:]
    }
    
    // 基底ハンドラーにも転送
    return h.handler.Handle(ctx, r)
}

func (h *BufferedHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
    return &BufferedHandler{
        buffer:  h.buffer,
        maxSize: h.maxSize,
        handler: h.handler.WithAttrs(attrs),
    }
}

func (h *BufferedHandler) WithGroup(name string) slog.Handler {
    return &BufferedHandler{
        buffer:  h.buffer,
        maxSize: h.maxSize,
        handler: h.handler.WithGroup(name),
    }
}

func (h *BufferedHandler) GetBuffer() []LogEntry {
    h.mu.Lock()
    defer h.mu.Unlock()
    
    result := make([]LogEntry, len(h.buffer))
    copy(result, h.buffer)
    return result
}

func (h *BufferedHandler) ClearBuffer() {
    h.mu.Lock()
    defer h.mu.Unlock()
    
    h.buffer = h.buffer[:0]
}

// ログレベル変更可能なハンドラー
type DynamicLevelHandler struct {
    levelVar *slog.LevelVar
    handler  slog.Handler
}

func NewDynamicLevelHandler(initialLevel slog.Level, underlying slog.Handler) *DynamicLevelHandler {
    levelVar := &slog.LevelVar{}
    levelVar.Set(initialLevel)
    
    return &DynamicLevelHandler{
        levelVar: levelVar,
        handler:  underlying,
    }
}

func (h *DynamicLevelHandler) Enabled(ctx context.Context, level slog.Level) bool {
    return level >= h.levelVar.Level()
}

func (h *DynamicLevelHandler) Handle(ctx context.Context, r slog.Record) error {
    if !h.Enabled(ctx, r.Level) {
        return nil
    }
    return h.handler.Handle(ctx, r)
}

func (h *DynamicLevelHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
    return &DynamicLevelHandler{
        levelVar: h.levelVar,
        handler:  h.handler.WithAttrs(attrs),
    }
}

func (h *DynamicLevelHandler) WithGroup(name string) slog.Handler {
    return &DynamicLevelHandler{
        levelVar: h.levelVar,
        handler:  h.handler.WithGroup(name),
    }
}

func (h *DynamicLevelHandler) SetLevel(level slog.Level) {
    h.levelVar.Set(level)
}

func (h *DynamicLevelHandler) GetLevel() slog.Level {
    return h.levelVar.Level()
}

// アプリケーション状態監視
type AppMonitor struct {
    logger          *slog.Logger
    bufferedHandler *BufferedHandler
    dynamicHandler  *DynamicLevelHandler
    metrics         map[string]interface{}
    mu              sync.RWMutex
}

func NewAppMonitor() *AppMonitor {
    // 基底ハンドラー(JSON)
    baseHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
        AddSource: true,
    })
    
    // バッファリングハンドラー
    bufferedHandler := NewBufferedHandler(1000, baseHandler)
    
    // 動的レベルハンドラー
    dynamicHandler := NewDynamicLevelHandler(slog.LevelInfo, bufferedHandler)
    
    logger := slog.New(dynamicHandler)
    
    return &AppMonitor{
        logger:          logger,
        bufferedHandler: bufferedHandler,
        dynamicHandler:  dynamicHandler,
        metrics:         make(map[string]interface{}),
    }
}

func (m *AppMonitor) SetLogLevel(level slog.Level) {
    m.dynamicHandler.SetLevel(level)
    m.logger.Info("ログレベル変更",
        "old_level", m.dynamicHandler.GetLevel(),
        "new_level", level,
    )
}

func (m *AppMonitor) UpdateMetric(key string, value interface{}) {
    m.mu.Lock()
    defer m.mu.Unlock()
    
    m.metrics[key] = value
    
    m.logger.Debug("メトリクス更新",
        "metric", key,
        "value", value,
    )
}

func (m *AppMonitor) LogMetrics() {
    m.mu.RLock()
    defer m.mu.RUnlock()
    
    attrs := make([]any, 0, len(m.metrics)*2)
    for k, v := range m.metrics {
        attrs = append(attrs, k, v)
    }
    
    m.logger.Info("現在のメトリクス", attrs...)
}

func (m *AppMonitor) GetRecentLogs(count int) []LogEntry {
    buffer := m.bufferedHandler.GetBuffer()
    if len(buffer) <= count {
        return buffer
    }
    return buffer[len(buffer)-count:]
}

func (m *AppMonitor) ExportLogs(writer io.Writer) error {
    buffer := m.bufferedHandler.GetBuffer()
    
    for _, entry := range buffer {
        attrs := make([]string, 0, len(entry.Attrs))
        for _, attr := range entry.Attrs {
            attrs = append(attrs, fmt.Sprintf("%s=%v", attr.Key, attr.Value))
        }
        
        line := fmt.Sprintf("[%s] %s %s %s\n",
            entry.Time.Format("2006-01-02 15:04:05"),
            entry.Level,
            entry.Message,
            strings.Join(attrs, " "),
        )
        
        if _, err := writer.WriteString(line); err != nil {
            return err
        }
    }
    
    return nil
}

// 業務ロジックの例
func simulateBusinessLogic(monitor *AppMonitor) {
    ctx := context.Background()
    
    monitor.logger.InfoContext(ctx, "業務処理開始",
        "module", "business_logic",
        "version", "2.1.0",
    )
    
    // メトリクス更新のシミュレーション
    for i := 0; i < 10; i++ {
        monitor.UpdateMetric("processed_items", i+1)
        monitor.UpdateMetric("success_rate", 95.5+float64(i)*0.1)
        monitor.UpdateMetric("active_connections", 50+i*5)
        
        monitor.logger.DebugContext(ctx, "処理中",
            "iteration", i+1,
            "status", "processing",
        )
        
        time.Sleep(100 * time.Millisecond)
        
        // エラーのシミュレーション
        if i == 7 {
            monitor.logger.WarnContext(ctx, "一時的なエラー",
                "iteration", i+1,
                "error", "temporary_failure",
                "retry_needed", true,
            )
        }
    }
    
    monitor.LogMetrics()
    
    monitor.logger.InfoContext(ctx, "業務処理完了",
        "total_processed", 10,
        "duration", "1s",
        "status", "success",
    )
}

func main() {
    monitor := NewAppMonitor()
    
    monitor.logger.Info("アプリケーション開始",
        "pid", os.Getpid(),
        "go_version", "1.21",
        "build_time", time.Now().Format(time.RFC3339),
    )
    
    // 初期はINFOレベル
    monitor.logger.Debug("このメッセージは表示されません")
    monitor.logger.Info("このメッセージは表示されます")
    
    // ログレベルをDEBUGに変更
    monitor.SetLogLevel(slog.LevelDebug)
    monitor.logger.Debug("ログレベル変更後:このメッセージは表示されます")
    
    // 業務ロジック実行
    simulateBusinessLogic(monitor)
    
    // ログレベルをWARNに変更
    monitor.SetLogLevel(slog.LevelWarn)
    monitor.logger.Info("このメッセージは表示されません(WARNレベル)")
    monitor.logger.Warn("このメッセージは表示されます")
    
    // 最近のログを取得
    recentLogs := monitor.GetRecentLogs(5)
    fmt.Printf("\n=== 最近の5件のログ ===\n")
    for _, log := range recentLogs {
        fmt.Printf("[%s] %s %s\n", 
            log.Time.Format("15:04:05"), 
            log.Level, 
            log.Message)
    }
    
    // ログをファイルにエクスポート
    file, err := os.Create("application.log")
    if err == nil {
        defer file.Close()
        if err := monitor.ExportLogs(file); err != nil {
            monitor.logger.Error("ログエクスポートエラー", "error", err)
        } else {
            monitor.logger.Info("ログエクスポート完了", "file", "application.log")
        }
    }
    
    monitor.logger.Info("アプリケーション終了")
}

パフォーマンス最適化とベンチマーク

package main

import (
    "context"
    "fmt"
    "log/slog"
    "os"
    "runtime"
    "sync"
    "time"
)

// ハイパフォーマンス用のカスタムハンドラー
type HighPerformanceHandler struct {
    mu     sync.Mutex
    writer *os.File
    buffer []byte
}

func NewHighPerformanceHandler(filename string) (*HighPerformanceHandler, error) {
    file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
    if err != nil {
        return nil, err
    }
    
    return &HighPerformanceHandler{
        writer: file,
        buffer: make([]byte, 0, 1024), // 1KBバッファ
    }, nil
}

func (h *HighPerformanceHandler) Enabled(ctx context.Context, level slog.Level) bool {
    return level >= slog.LevelInfo // INFOレベル以上のみ
}

func (h *HighPerformanceHandler) Handle(ctx context.Context, r slog.Record) error {
    h.mu.Lock()
    defer h.mu.Unlock()
    
    // 高速フォーマット(最小限の文字列操作)
    h.buffer = h.buffer[:0]
    h.buffer = append(h.buffer, r.Time.Format("15:04:05")...)
    h.buffer = append(h.buffer, ' ')
    h.buffer = append(h.buffer, r.Level.String()...)
    h.buffer = append(h.buffer, ' ')
    h.buffer = append(h.buffer, r.Message...)
    h.buffer = append(h.buffer, '\n')
    
    _, err := h.writer.Write(h.buffer)
    return err
}

func (h *HighPerformanceHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
    return h // 簡単化のため属性は無視
}

func (h *HighPerformanceHandler) WithGroup(name string) slog.Handler {
    return h // 簡単化のためグループは無視
}

func (h *HighPerformanceHandler) Close() error {
    return h.writer.Close()
}

// パフォーマンステスト
func benchmarkLogging() {
    fmt.Println("=== ロギングパフォーマンステスト ===")
    
    // テスト設定
    iterations := 100000
    
    // 1. 標準のJSONハンドラー
    jsonHandler := slog.NewJSONHandler(os.Stdout, nil)
    jsonLogger := slog.New(jsonHandler)
    
    start := time.Now()
    for i := 0; i < iterations; i++ {
        jsonLogger.Info("テストメッセージ",
            "iteration", i,
            "timestamp", time.Now().Unix(),
        )
    }
    jsonDuration := time.Since(start)
    
    // 2. 標準のTextハンドラー
    textHandler := slog.NewTextHandler(os.Stdout, nil)
    textLogger := slog.New(textHandler)
    
    start = time.Now()
    for i := 0; i < iterations; i++ {
        textLogger.Info("テストメッセージ",
            "iteration", i,
            "timestamp", time.Now().Unix(),
        )
    }
    textDuration := time.Since(start)
    
    // 3. 高性能カスタムハンドラー
    hpHandler, err := NewHighPerformanceHandler("benchmark.log")
    if err != nil {
        panic(err)
    }
    defer hpHandler.Close()
    
    hpLogger := slog.New(hpHandler)
    
    start = time.Now()
    for i := 0; i < iterations; i++ {
        hpLogger.Info("テストメッセージ")
    }
    hpDuration := time.Since(start)
    
    // 結果表示
    fmt.Printf("JSON Handler: %v (%v ns/op)\n", 
        jsonDuration, jsonDuration.Nanoseconds()/int64(iterations))
    fmt.Printf("Text Handler: %v (%v ns/op)\n", 
        textDuration, textDuration.Nanoseconds()/int64(iterations))
    fmt.Printf("HP Handler: %v (%v ns/op)\n", 
        hpDuration, hpDuration.Nanoseconds()/int64(iterations))
}

// 並行ロギングテスト
func concurrentLoggingTest() {
    fmt.Println("\n=== 並行ロギングテスト ===")
    
    jsonHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
        Level: slog.LevelInfo,
    })
    logger := slog.New(jsonHandler)
    
    var wg sync.WaitGroup
    goroutines := 10
    messagesPerGoroutine := 1000
    
    start := time.Now()
    
    for i := 0; i < goroutines; i++ {
        wg.Add(1)
        go func(goroutineID int) {
            defer wg.Done()
            
            for j := 0; j < messagesPerGoroutine; j++ {
                logger.Info("並行ログメッセージ",
                    "goroutine_id", goroutineID,
                    "message_id", j,
                    "timestamp", time.Now().UnixNano(),
                )
            }
        }(i)
    }
    
    wg.Wait()
    duration := time.Since(start)
    
    totalMessages := goroutines * messagesPerGoroutine
    fmt.Printf("並行ログ: %d goroutines × %d messages = %d total messages\n",
        goroutines, messagesPerGoroutine, totalMessages)
    fmt.Printf("実行時間: %v (%v ns/message)\n",
        duration, duration.Nanoseconds()/int64(totalMessages))
}

// メモリ使用量テスト
func memoryUsageTest() {
    fmt.Println("\n=== メモリ使用量テスト ===")
    
    var m1, m2 runtime.MemStats
    runtime.GC()
    runtime.ReadMemStats(&m1)
    
    jsonHandler := slog.NewJSONHandler(os.Stdout, nil)
    logger := slog.New(jsonHandler)
    
    // 大量のログ出力
    for i := 0; i < 10000; i++ {
        logger.Info("メモリテストメッセージ",
            "iteration", i,
            "data", map[string]interface{}{
                "key1": "value1",
                "key2": 42,
                "key3": []string{"a", "b", "c"},
            },
        )
    }
    
    runtime.GC()
    runtime.ReadMemStats(&m2)
    
    fmt.Printf("ヒープアロケーション: %d bytes\n", m2.HeapAlloc-m1.HeapAlloc)
    fmt.Printf("総アロケーション: %d bytes\n", m2.TotalAlloc-m1.TotalAlloc)
    fmt.Printf("GC実行回数: %d\n", m2.NumGC-m1.NumGC)
}

// 条件付きロギングのパフォーマンステスト
func conditionalLoggingTest() {
    fmt.Println("\n=== 条件付きロギングテスト ===")
    
    // DEBUGレベルを無効にしたハンドラー
    handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
        Level: slog.LevelInfo,
    })
    logger := slog.New(handler)
    
    iterations := 1000000
    
    // 1. 常にdebugログを呼び出し(無効化されているので出力されない)
    start := time.Now()
    for i := 0; i < iterations; i++ {
        logger.Debug("デバッグメッセージ", "iteration", i)
    }
    disabledDuration := time.Since(start)
    
    // 2. 事前チェック付き
    start = time.Now()
    for i := 0; i < iterations; i++ {
        if logger.Enabled(context.Background(), slog.LevelDebug) {
            logger.Debug("デバッグメッセージ", "iteration", i)
        }
    }
    checkedDuration := time.Since(start)
    
    fmt.Printf("無効デバッグログ: %v (%v ns/call)\n",
        disabledDuration, disabledDuration.Nanoseconds()/int64(iterations))
    fmt.Printf("事前チェック付き: %v (%v ns/call)\n",
        checkedDuration, checkedDuration.Nanoseconds()/int64(iterations))
    fmt.Printf("パフォーマンス差: %.2fx\n",
        float64(disabledDuration)/float64(checkedDuration))
}

func main() {
    benchmarkLogging()
    concurrentLoggingTest()
    memoryUsageTest()
    conditionalLoggingTest()
    
    fmt.Println("\n=== パフォーマンステスト完了 ===")
    fmt.Println("benchmark.logファイルに結果が出力されました")
}