go-logging について
構造化ログ、レベル、コンテキスト単位のフィールド、機密データの扱いを解説する Go のログスキルです。プロダクションログの実装やレビューを行う開発者向けで、新規コードには標準ライブラリの `log/slog` を推奨します。
主な機能
- 01キーと値による構造化ログ
- 02ログレベルの選択
- 03コンテキスト単位のロガーフィールド
- 04機密データの除外
- 05ハンドラー設定とテストの指針
活用シーン
- 01Go サービスへの運用ログ追加
- 02エラーログと戻り値のレビュー
- 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を参照してください