logging-best-practices について
アプリケーションのログ設計やコードレビュー向けの開発スキルです。サービスごとにリクエスト単位で文脈豊かな構造化イベントを記録し、スキーマと業務・デプロイ情報を統一します。
主な機能
- 01リクエストごとにワイドイベントを記録
- 02リクエスト・業務・環境の情報を含める
- 03コードベースで単一のロガーを使用
- 04ミドルウェアでイベント基盤を処理
- 05JSONのフィールドとスキーマを統一
活用シーン
- 01新規サービスのログ設計
- 02アプリケーションのログコードのレビュー
- 03リクエストハンドラーへの構造化ログ追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ boristane/ agent-skills --skill logging-best-practicesインストール後、Claude Code で/logging-best-practicesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.jsonREADME.mdrules/context.mdpitfalls.mdstructure.mdwide-events.md詳細
ロギングのベストプラクティススキル
バージョン:1.0.0
目的
このスキルでは、アプリケーションで効果的なロギングを実装するためのガイドラインを紹介します。ワイドイベント(カノニカルログラインとも呼ばれます)に焦点を当てています。これは、サービスごとにリクエストあたり1つの、豊富なコンテキストを持つイベントを出力し、強力なデバッグと分析を可能にするパターンです。
適用するタイミング
以下の場合に、これらのガイドラインを適用してください。
- ロギングコードを記述またはレビューするとき
- console.log、logger.infoなどを追加するとき
- 新しいサービスのロギング戦略を設計するとき
- ロギングインフラストラクチャを設定するとき
基本原則
1. ワイドイベント(重要)
リクエストごとに、サービスあたり1つの、豊富なコンテキストを持つイベントを出力してください。ハンドラー内のあちこちにログを散在させるのではなく、すべてを1つの構造化イベントにまとめ、リクエスト完了時に出力します。
const wideEvent: Record<string, unknown> = {
method: 'POST',
path: '/checkout',
requestId: c.get('requestId'),
timestamp: new Date().toISOString(),
};
try {
const user = await getUser(c.get('userId'));
wideEvent.user = { id: user.id, subscription: user.subscription };
const cart = await getCart(user.id);
wideEvent.cart = { total_cents: cart.total, item_count: cart.items.length };
wideEvent.status_code = 200;
wideEvent.outcome = 'success';
return c.json({ success: true });
} catch (error) {
wideEvent.status_code = 500;
wideEvent.outcome = 'error';
wideEvent.error = { message: error.message, type: error.name };
throw error;
} finally {
wideEvent.duration_ms = Date.now() - startTime;
logger.info(wideEvent);
}
2. 高カーディナリティと高次元性(重要)
カーディナリティの高いフィールド(ユーザーID、リクエストIDなど、数百万もの一意な値)と、次元性の高いフィールド(イベントあたりのフィールド数が多い)を含めてください。これにより、特定のユーザーでクエリを実行したり、想定していなかった質問に答えたりできます。
3. ビジネスコンテキスト(重要)
常にビジネスコンテキストを含めてください。ユーザーのサブスクリプションティア、カートの金額、フィーチャーフラグ、アカウントの利用期間などです。目指すのは、単に「チェックアウトに失敗した」と記録するのではなく、「プレミアム顧客が2,499ドルの購入を完了できなかった」と把握できることです。
4. 環境特性(重要)
すべてのイベントに環境とデプロイに関する情報を含めてください。コミットハッシュ、サービスのバージョン、リージョン、インスタンスIDなどです。これにより、問題とデプロイを関連付け、特定のリージョンに固有の問題を特定できます。
5. ロガーを1つにする(高)
起動時に設定したロガーインスタンスを1つ使用し、すべての場所でインポートしてください。これにより、フォーマットの一貫性が保たれ、環境コンテキストが自動的に追加されます。
6. ミドルウェアパターン(高)
ミドルウェアを使用して、ワイドイベントの基盤(計測時間、ステータス、環境、出力)を処理してください。ハンドラーではビジネスコンテキストのみを追加します。
7. 構造と一貫性(高)
- 一貫してJSON形式を使用する
- サービス間でフィールド名に一貫性を持たせる
- ログレベルを
infoとerrorの2つに簡素化する - 構造化されていない文字列を決してログに記録しない
避けるべきアンチパターン
- ログの散在:リクエストごとに複数のconsole.log()を呼び出す
- 複数のロガー:ファイルごとに異なるロガーインスタンスを使用する
- 環境コンテキストの欠落:コミットハッシュやデプロイ情報がない
- ビジネスコンテキストの欠落:ユーザーやビジネスのデータを含めず、技術的な詳細のみを記録する
- 構造化されていない文字列:構造化データではなく、
console.log('something happened')を使用する - 一貫性のないスキーマ:サービス間でフィールド名が異なる
ガイドライン
ワイドイベント(rules/wide-events.md)
- サービスの各ホップにつき、ワイドイベントを1つ出力する
- 関連するすべてのコンテキストを含める
- リクエストIDでイベントを関連付ける
- finallyブロックでリクエスト完了時に出力する
コンテキスト(rules/context.md)
- カーディナリティの高いフィールド(user_id、request_id)をサポートする
- 次元性の高さ(多数のフィールド)を確保する
- 常にビジネスコンテキストを含める
- 常に環境特性(commit_hash、version、region)を含める
構造(rules/structure.md)
- コードベース全体でロガーを1つ使用する
- 一貫したワイドイベントにはミドルウェアを使用する
- JSON形式を使用する
- 一貫したスキーマを維持する
- ログレベルをinfoとerrorに簡素化する
- 構造化されていない文字列を決してログに記録しない
よくある落とし穴(rules/pitfalls.md)
- リクエストごとに複数のログ行を出力しない
- まだ知られていない未知の問題にも対応できるよう設計する
- サービス間でリクエストIDを常に伝播させる
参考資料: