スキップしてメイン コンテンツに移動

Goログzapで構造化監視

Goログzapで構造化監視

Go実践でのロギングの重要性

Goで開発する際、ロギングはデバッグだけでなく運用監視や障害対応に不可欠です。標準パッケージ log は簡易的なログ出力に便利ですが、構造化ログやログレベルの制御が難しいため、実運用ではより高度なロギングライブラリが選ばれます。Go実践では、ログを単なる文字列ではなく、JSON などの構造化データとして出力し、監視ツールと連携させることが推奨されます。

log, zap, zerolog の比較

Go のロギングライブラリは多数ありますが、代表的なものに logzapzerolog があります。以下に主な特徴をまとめます。

  • log:標準ライブラリ。シンプルだが構造化ログや高速化は不可。デバッグ時に便利。
  • zap:Uber が開発。高速で構造化ログが可能。ログレベルを細かく制御でき、JSON 出力がデフォルト。
  • zerolog:ゼロコピーで高速。構造化ログが標準で、ログレベルも柔軟に設定可能。

実際にプロジェクトで選択する際は、パフォーマンス要件とログの可読性・機能性を比較して決定します。

package main

import (
    "go.uber.org/zap"
    "github.com/rs/zerolog"
    "log"
)

func main() {
    // 標準log
    log.Println("Hello, log")

    // zap
    logger, _ := zap.NewProduction()
    defer logger.Sync()
    logger.Info("Hello, zap", zap.String("key", "value"))

    // zerolog
    zerolog.SetGlobalLevel(zerolog.InfoLevel)
    log := zerolog.New(os.Stdout).With().Timestamp().Logger()
    log.Info().Str("key", "value").Msg("Hello, zerolog")
}

構造化ログとログレベルの設計

構造化ログは、ログを JSON 形式で出力し、キーと値のペアで情報を表現します。これにより、ログ検索や可視化が容易になります。ログレベルは DEBUGINFOWARNERROR などを設定し、運用時に必要な情報量を制御します。

例として、zap で構造化ログとログレベルを設定する方法を示します。

logger, _ := zap.NewProduction()
defer logger.Sync()

// DEBUG レベルのログ
logger.Debug("debug message", zap.Int("id", 123))

// INFO レベルのログ
logger.Info("info message", zap.String("user", "alice"))

// WARN レベルのログ
logger.Warn("warn message", zap.Error(err))

// ERROR レベルのログ
logger.Error("error message", zap.Error(err))

このように、ログレベルを適切に使い分けることで、デバッグ時の情報過多を防ぎ、監視時に重要なイベントだけを抽出できます。

ローテーション・出力先とデバッグ・監視

ログファイルが膨大になるとディスク容量を圧迫します。ローテーションは、一定サイズや日付でファイルを分割し、古いログをアーカイブまたは削除する仕組みです。zap と zerolog にはローテーション機能を持つ拡張パッケージが存在します。

  • zap の zapcore.AddSynclumberjack を組み合わせる。
  • zerolog の zerolog.Newlumberjack で同様にローテーションを実装。

出力先はファイルだけでなく、標準出力や syslog、クラウドのログサービス(CloudWatch、Stackdriver など)へも設定できます。デバッグ時は DEBUG レベルを有効にし、運用時は INFO 以上に切り替えることで、必要な情報だけを残すことができます。

import (
    "go.uber.org/zap"
    "gopkg.in/natefinch/lumberjack.v2"
)

func newLogger() (*zap.Logger, error) {
    lumberjackLogger := &lumberjack.Logger{
        Filename:   "/var/log/app.log",
        MaxSize:    100, // MB
        MaxBackups: 7,
        MaxAge:     30, // days
    }
    return zap.New(zapcore.NewCore(
        zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
        zapcore.AddSync(lumberjackLogger),
        zap.InfoLevel,
    ))
}

こうした設定を行うことで、デバッグと監視の両方に対応した堅牢なロギング基盤を構築できます。

この記事はAIによって作成されました。

コメント