mcpField
G
go-logging

go-logging

github.com/cxuu開発1861.1k 回インストール19 週間前に更新
リポジトリ

go-logging について

構造化ログ、レベル、コンテキスト単位のフィールド、機密データの扱いを解説する Go のログスキルです。プロダクションログの実装やレビューを行う開発者向けで、新規コードには標準ライブラリの `log/slog` を推奨します。

主な機能

  1. 01キーと値による構造化ログ
  2. 02ログレベルの選択
  3. 03コンテキスト単位のロガーフィールド
  4. 04機密データの除外
  5. 05ハンドラー設定とテストの指針

活用シーン

  1. 01Go サービスへの運用ログ追加
  2. 02エラーログと戻り値のレビュー
  3. 03ログへの認証情報や個人データの混入防止

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/cxuu/golang-skills --skill go-logging

インストール後、Claude Code で/go-loggingを入力して読み込まれたか確認します。

同梱ファイルreferences/LEVELS-AND-CONTEXT.mdreferences/LOGGING-PATTERNS.md

詳細

Go のロギング

互換性:log/slog には Go 1.21 以降が必要です。testing/slogtest には Go 1.22 以降が必要です。

リソースのルーティング

  • references/LEVELS-AND-CONTEXT.md - ログレベルの選択、コンテキストにロガーを含めるか明示的なパラメーターを使うかの判断、機密フィールドの除外について確認する場合に読みます。
  • references/LOGGING-PATTERNS.md - slog ハンドラーの設定、HTTP リクエストのロギング、ハンドラーのテスト、log.Printf からの移行について確認する場合に読みます。

基本原則

ログは開発者ではなく、運用担当者のためのものです。すべてのログ行は、誰かが本番環境の問題を診断するのに役立つものであるべきです。その目的に役立たないものは、ノイズです。


ロガーの選択

規範:新しい Go コードでは log/slog を使用します。

slog は構造化され、レベル分けされており、標準ライブラリに含まれています(Go 1.21 以降)。本番環境で必要となるロギングの大半に対応できます。

Which logger?
├─ New production code      → log/slog
├─ Trivial CLI / one-off    → log (standard)
└─ Measured perf bottleneck → zerolog or zap (benchmark first)

プロファイリングにより、ホットパスで slog がボトルネックになっていると確認されない限り、サードパーティ製のロギングライブラリを導入しないでください。導入する場合も、同じ構造化されたキーと値の形式を維持してください。


構造化ロギング

規範:常にキーと値のペアを使用します。メッセージ文字列に値を埋め込んではいけません。

メッセージは、何が起きたかを示す静的な説明です。動的なデータはキーと値の属性に含めます。

// Good: static message, structured fields
slog.Info("order placed", "order_id", orderID, "total", total)

// Bad: dynamic data baked into the message string
slog.Info(fmt.Sprintf("order %d placed for $%.2f", orderID, total))
キーの命名

推奨:ログ属性のキーには snake_case を使用します。

キーは小文字で、アンダースコア区切りとし、コードベース全体で一貫させます。例:user_id、request_id、elapsed_ms。

型付き属性

パフォーマンスが重要なパスでは、割り当てを避けるために型付きコンストラクターを使用します。

slog.LogAttrs(ctx, slog.LevelInfo, "request handled",
    slog.String("method", r.Method),
    slog.Int("status", code),
    slog.Duration("elapsed", elapsed),
)

ログレベル

推奨:以下のレベルの意味を一貫して適用します。

レベル使用する場面本番環境での既定値
Debug開発者向けの診断、内部状態の追跡無効
Info起動、終了、設定の読み込みなど、注目すべきライフサイクルイベント有効
Warn予期しないが復旧可能な状況:非推奨機能の使用、リトライの成功有効
Error操作の失敗、運用担当者による対応が必要有効

判断の目安:

  • 誰も対応する必要がないなら Error ではありません。Warn または Info を使用します
  • デバッガーを接続しているときにしか役立たないなら Debug です
  • slog.Error には常に "err" 属性を含めます
slog.Error("payment failed", "err", err, "order_id", id)
slog.Warn("retry succeeded", "attempt", n, "endpoint", url)
slog.Info("server started", "addr", addr)
slog.Debug("cache lookup", "key", key, "hit", hit)

リクエストスコープのロギング

推奨:コンテキストからロガーを派生させ、リクエストスコープのフィールドを引き継ぎます。

ミドルウェアを使ってリクエスト ID、ユーザー ID、トレース ID をロガーに追加し、そのロガーをコンテキスト経由または明示的なパラメーターとして後続処理に渡します。リクエストスコープのロギングを一元管理できるよう、コンテキストキーとミドルウェアの実装全体はロギングパターンのリファレンスに記載します。


ログに記録するか返すかのどちらかにする

一度だけ処理するルールは、go-error-handling に記載されています。ロギングでは、同じエラーに対して、ローカルでログに記録して復旧する方法か、コンテキストを付けて返す方法のどちらかを選び、両方を行わないようにします。

例外:HTTP ハンドラーなどの最上位の境界では、サーバー側で詳細なエラーをログに記録しつつ、クライアントにはサニタイズしたメッセージを返してもかまいません。

if err != nil {
    slog.Error("checkout failed", "err", err, "user_id", uid)
    http.Error(w, "internal error", http.StatusInternalServerError)
    return
}

一度だけ処理するパターン全体とエラーのラップ方法については、go-error-handling を参照してください。


ログに記録してはいけないもの

規範:シークレット、認証情報、PII、またはカーディナリティが高く上限のないデータをログに記録してはいけません。

  • パスワード、API キー、トークン、セッション ID
  • クレジットカード番号全体、SSN
  • ユーザーデータが含まれる可能性のあるリクエスト/レスポンスボディ
  • サイズに上限のないスライスやマップ全体

クイックリファレンス

することしないこと
slog.Info("msg", "key", val)log.Printf("msg %v", val)
静的なメッセージ+構造化フィールドメッセージ内での fmt.Sprintf
snake_case のキーcamelCase または一貫性のないキー
エラーをログに記録するか、返すかのどちらかにする同じエラーをログに記録して返す
コンテキストからロガーを派生させる呼び出しごとに新しいロガーを作成する
"err" 属性を付けて slog.Error を使用するエラーに slog.Info を使用する
ホットパスでは Enabled() を事前に確認する常にログ引数を割り当てる

関連するスキル

  • エラー処理:エラーをログに記録するか返すかを判断するときや、1 回だけ処理するパターンについては、go-error-handlingを参照してください
  • コンテキストの伝播:ロガーを含むリクエストスコープの値をコンテキスト経由で渡すときは、go-contextを参照してください
  • パフォーマンス:ホットパスのロギングを最適化するときや、ログ呼び出しでのアロケーションを削減するときは、go-performanceを参照してください
  • コードレビュー:Go の PR でロギングの実践方法をレビューするときは、go-code-reviewを参照してください

コメント