Agent Skills by ALSEL
汎用ソフトウェア開発⭐ リポ 4品質スコア 76/100

improve-logging

コードベース全体のログ品質を監査・改善します。ユーザーが「ログを改善したい」「ログレベルを修正したい」「ログを追加したい」「ログをレビューしてほしい」「ログを統一したい」「ログが不十分」といったリクエストや、ログメッセージが不明確、不足している、または重要度が不適切といった問題について質問した場合に使用してください。優先度付けされた改善提案のリストを生成します。ファイルは直接編集しません。

description の原文を見る

Audit and improve logging quality across a codebase. Use when the user asks to "improve logging", "fix log levels", "add logging", "review our logs", "make logging consistent", "we have bad logging", or anything about log messages being unclear, missing, or at the wrong severity. Produces a prioritized list of recommendations — does not edit files directly.

SKILL.md 本文

ログの改善

コードベースのログを監査し、3つの領域をカバーする優先順位付けされた推奨事項リストを作成します:ログステートメントの欠落、不適切な重大度レベル、メッセージ品質の低さです。また、アプリケーション全体で一貫したログパターンを実施(または提案)します。

このスキルは読み取り専用です。 推奨事項レポートを作成します。ファイルは直接編集しません。

タスク追跡

作業を開始する前に、以下の各フェーズに対して TaskCreate を呼び出してください。フェーズを開始する時は TaskUpdate(ステータス in_progress)を、終了する時は TaskUpdate(ステータス completed)を呼び出してください。

  • 言語とログフレームワークを検出
  • ログパターンを確立
  • 問題をスキャン
  • レポートを作成

フェーズ 1:言語とログフレームワークを検出

# 言語を特定
find . -maxdepth 4 -not -path "*/.git/*" -not -path "*/node_modules/*" \
  -not -path "*/vendor/*" -not -path "*/.venv/*" \
  \( -name "*.py" -o -name "*.java" -o -name "*.kt" -o -name "*.ts" \
     -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.go" \
     -o -name "*.rs" -o -name "*.cs" -o -name "*.rb" \) \
  | sed 's/.*\.//' | sort | uniq -c | sort -rn | head -10

言語ごとに使用中のログフレームワークを検出します:

言語検出するフレームワーク
Pythonimport logging, from loguru, import structlog
Java/Kotlinimport org.slf4j, import org.apache.logging, import io.github.oshai
TypeScript/JSimport winston, import pino, console.log/warn/error
Goimport "log", "go.uber.org/zap", "github.com/sirupsen/logrus"
C#ILogger, Microsoft.Extensions.Logging, Serilog, NLog
RubyRails.logger, Logger.new
# Python
grep -rn "import logging\|from loguru\|import structlog" --include="*.py" . | head -5

# Java/Kotlin
grep -rn "import org.slf4j\|import org.apache.logging\|LoggerFactory\|KotlinLogging" \
  --include="*.java" --include="*.kt" . | head -5

# TypeScript/JS
grep -rn "require.*winston\|require.*pino\|import.*winston\|import.*pino\|console\.\(log\|warn\|error\|info\|debug\)" \
  --include="*.ts" --include="*.js" --include="*.tsx" --include="*.jsx" . | head -5

# Go
grep -rn '"log"\|"go.uber.org/zap"\|"github.com/sirupsen/logrus"\|"golang.org/x/exp/slog"' \
  --include="*.go" . | head -5

フェーズ 2:ログパターンを確立

現在のパターン(またはパターンの欠如)を理解するため、既存のログ呼び出しサイトから最大 20 個をサンプリングします:

# Python の例 — ログ呼び出しを検出
grep -rn "logger\.\|logging\." --include="*.py" . | head -20

# Java/Kotlin の例
grep -rn "log\.\(info\|debug\|warn\|error\|trace\)" --include="*.java" --include="*.kt" . | head -20

# Go の例
grep -rn "log\.\|logger\.\|zap\.\|logrus\." --include="*.go" . | head -20

ログが存在する代表的な 3~5 個のファイルを読んで、以下を理解します:

  1. メッセージスタイル — 動詞優先(「Processing request」)、名詞優先(「Request received」)、または混在?
  2. コンテキストフィールド — 構造化フィールドが使用されているか(例:log.Info("done", "user_id", id))?どのフィールドが一貫して現れるか?
  3. ロガーのインスタンス化 — モジュールレベルのシングルトン、コンテキスト経由で渡される、または関数ごとに作成される?
  4. レベル規律 — DEBUG は細粒度トレースに使用されるか?INFO はビジネスイベント用か?

必須フィールド

すべてのログ呼び出しには最低限以下が含まれる必要があります:

フィールド目的必須条件
イベント名何が起きたか(メッセージ)常に
request_id / trace_idリクエスト全体でログを相関させる受信リクエスト(HTTP、gRPC、キュー消費者)を処理するコード
user_idアクションをトリガーしたのは誰かユーザーID がスコープ内にあるユーザーに面したオペレーション
error / errエラー値またはメッセージWARN 以上のレベルのログ

コードベースがこれらのフィールドを既に一貫して使用している場合、それらを必須として文書化します。そうでない場合は、提案されるパターンに含めます。リクエストスコープコード内にあるが request_id / trace_id を省略しているログ呼び出しをフラグとして、矛盾(フェーズ 3d)として報告します。

パターン決定

  • 明確なパターンが存在する場合(一貫したメッセージスタイル、一貫したフィールド、一貫したロガーのインスタンス化):それを文書化し、任意の逸脱を矛盾した発見として扱います。
  • 明確なパターンが存在しない場合(コードベース全体で 5 個未満のログ呼び出し、または非常に矛盾している):言語とフレームワークに適したパターンを提案します。ユーザーが推奨事項に対応する前に承認または調整できるように、レポートの最初に提案されたパターンを明記します。

フレームワーク別の推奨パターン:

Python (structlog または logging):

log = structlog.get_logger(__name__)
log.info("order.placed", order_id=order_id, user_id=user_id)
# メッセージ:noun.verb スネークケース、コンテキストはキーワード引数

Go (zap または slog):

logger.Info("order placed", zap.String("order_id", orderID), zap.String("user_id", userID))
// メッセージ:小文字の散文、コンテキストは型付きフィールド

Java/Kotlin (SLF4J):

log.info("Order placed: orderId={}, userId={}", orderId, userId);
// メッセージ:文体の散文、コンテキストは SLF4J プレースホルダー経由

TypeScript/JS (pino または winston):

logger.info({ orderId, userId }, 'Order placed')
// pino スタイル:コンテキストオブジェクト優先、メッセージは次点

フェーズ 3:問題をスキャン

3a. ログステートメントの欠落

ログが出力されるべきだが出力されていないコードパスを探します。高価値の場所に焦点を当てます:

ログのないエラーハンドラー:

# Python
grep -rn "except " --include="*.py" -A 3 . | grep -v "log\|logger\|print" | head -20

# Java
grep -rn "catch\s*(" --include="*.java" -A 3 . | grep -v "log\.\|LOG\.\|logger\." | head -20

# Go
grep -rn "if err != nil" --include="*.go" -A 2 . | grep -v "log\.\|logger\." | head -20

# TypeScript
grep -rn "catch\s*(" --include="*.ts" --include="*.js" -A 3 . | grep -v "console\.\|logger\.\|log\." | head -20

重要なオペレーションで周辺ログなし — これらの grep パターンを使用して高価値関数を見つけ、それらを読んでログが出力されているか確認します:

# 状態変更または副作用を示す名前の関数
grep -rn "def \(create\|update\|delete\|remove\|send\|publish\|process\|handle\|execute\|run\|dispatch\)_" \
  --include="*.py" .

grep -rn "func \(create\|update\|delete\|remove\|send\|publish\|process\|handle\|execute\|run\|dispatch\)[A-Z]" \
  --include="*.go" .

grep -rn "^\s*\(public\|private\|protected\).*\(create\|update\|delete\|send\|process\|handle\)[A-Z]" \
  --include="*.java" --include="*.kt" .

grep -rn "^\(export \)\?\(async \)\?function \(create\|update\|delete\|send\|process\|handle\)" \
  --include="*.ts" --include="*.js" .

名前に関係なく、これらの場所も確認します:

  • HTTP ハンドラー / ルートコントローラー(handlers/controllers/routes/views/ 内のファイル)
  • バックグラウンドジョブ / スケジュール済みタスク(jobs/workers/tasks/cron/
  • スタートアップおよびシャットダウンシーケンス(メインエントリーポイント、init()、シグナルハンドラー)

以下の場合、操作をログ欠落としてフラグを付けます:

  • エラーパスを処理しているが、ログがない
  • 重要な状態変更(作成、更新、削除)を完了しているが、ログがない
  • 外部サービスを呼び出しているが、失敗時にログがない
  • 再スロー(キャッチされて即座に再スロー)でログが再スロー前にない — 呼び出し元も ログしない可能性があるため、これが最後のチャンスです

3b. 不適切な重大度レベル

発見されたログ呼び出しそれぞれについて、レベルが状況に合致しているか評価します。これらのルールを適用します:

レベル使用する時機よくある間違い
DEBUG開発中に役立つ実装詳細、本番環境では無効本番環境でオペレーターが見る必要があるイベントに DEBUG を使用
INFO正常で期待されるアプリケーション フロー、重要なビジネスイベントループ内のすべての行を INFO としてログ、回復可能エラーに INFO
WARN予期しないことが起きたが、アプリケーションは回復、後の問題を引き起こす可能性のある状態実際のエラーに WARN を使用、日常的なことに WARN を使用
ERRORオペレーションが失敗し、注意が必要、ユーザーまたはデータに影響する可能性エラーを静かに隠す、エラーを WARN としてログ
FATAL / CRITICALアプリケーションは続行できない、すぐにシャットダウン回復可能なエラーに FATAL を過度に使用

例外処理ルール — エラーハンドリングパスを読むときにこれらを正確に適用します:

状況正確なレベル理由
例外がキャッチされ再スローERRORオペレーションは失敗、呼び出し元は例外を見ます。呼び出し元がログしなくても少なくとも 1 つのレコードがあるようにここでログしてください。
例外がキャッチされ処理(リクエストは成功)WARN予期しないことが起きましたが、回復しました。
例外がキャッチされ隠蔽(再スローなし、レスポンス変更なし)ログ欠落としてフラグ静かな隠蔽は失敗を完全に隠します。隠蔽する前に必ずログしてください。
予期された、日常的な状態(キャッシュミス、404 ルックアップなど)DEBUG またはログなしエラーではなく、WARN/ERROR の高ボリュームイベントはアラーティングを汚染します。

HTTP ステータスコード → ログレベルマッピング — コードが HTTP ステータスを設定または返す場合、ログレベルは以下に従う必要があります:

ステータス範囲ログレベル理由
2xxINFO(またはフレームワークがリクエストをログする場合、ログなし)成功 — 通常のフロー
3xxDEBUGリダイレクト — 予期される、低価値
4xx(クライアントエラー)WARNクライアントが悪いリクエストを出した、サーバーは問題なし
5xx(サーバーエラー)ERRORサーバーは失敗、注意が必要
# 不適切なレベルでログされた HTTP レスポンス (Python/Flask/FastAPI)
grep -rn "status_code\s*=\s*[45][0-9][0-9]\|return.*[45][0-9][0-9]" --include="*.py" -A 3 . | \
  grep "logger\.\(debug\|info\|warning\)"

# 5xx が WARN の代わりに ERROR でログ (JS/TS)
grep -rn "res\.status(5[0-9][0-9])" --include="*.ts" --include="*.js" -A 5 . | \
  grep "console\.warn\|logger\.warn"

# 4xx が ERROR でログ(過度なアラーティング)
grep -rn "res\.status(4[0-9][0-9])" --include="*.ts" --include="*.js" -A 5 . | \
  grep "console\.error\|logger\.error"

また、以下をスキャンします:

# INFO または WARN でログされたエラー (Python)
grep -rn "logger\.info\|logging\.info\|logger\.warning" --include="*.py" . | grep -i "error\|fail\|exception\|crash"

# キャッチされ DEBUG でログされた例外
grep -rn "\.debug(" --include="*.java" --include="*.kt" . | grep -i "exception\|error\|fail"

# JS/TS でエラーに使用される console.log
grep -rn "console\.log" --include="*.ts" --include="*.js" . | grep -i "error\|fail\|exception"

代表的なファイル内のエラーハンドリングパスを読み込みます — grep は明らかな不一致をキャッチしますが、読むことで、より微妙なものが明らかになります(例:再スロー前のログなし)。

3c. 削除するログ

改善されるべきではなく、完全に削除すべきログ呼び出しをスキャンします。すべての一致をフラグしてください — これらは最優先の推奨事項です。機密データがログに含まれることはセキュリティインシデントが起きる寸前だからです。

機密データ:

# ログ引数内の一般的な機密フィールド名
grep -rn "password\|passwd\|secret\|api_key\|apikey\|token\|credential\|ssn\|credit_card\|cvv\|private_key" \
  --include="*.py" --include="*.java" --include="*.ts" --include="*.js" --include="*.go" --include="*.rb" . \
  | grep -i "log\|logger\|print\|console" | head -30

機密フィールドをパラメーターとして渡すか、メッセージ文字列に含めるログ呼び出しをフラグします。セキュリティリスクについて明確に説明を含めます(例:「ログ内の API キーはプレーンテキストで保存され、ログアクセス権を持つ誰もが、ログ集約サービスを含めてアクセスできます」)。

デバッグアーティファクト: Python の print()、JS/TS の console.log() / console.debug()、Go の fmt.Println()、Java の System.out.println() — これらは本番コードで意図的に使用されることはほぼありません。すべてをフラグします。

ログスパム: 各反復で発火する厳密なループ(for/while)内のログ呼び出し。大量項目の単一 INFO ログは数百万のログエントリを作成します。ループ後の集約ログに置き換えることを提案します(例:"Processed N items in Xms")。

冗長ログ: 同じイベントに対して同じレベルで数行内に複数のログ呼び出しがあり、どちらか一方は明らかに他方を包含します。

3d. メッセージ品質が低い

良いログメッセージは以下に答えます:何が起きたか、どのコンテキストで、そしてなぜそれが重要か?

以下のメッセージをフラグします:

  • 対応するには曖昧すぎる:"Error""Something went wrong""Failed""null""done""ok"
  • コンテキストが利用可能な時にコンテキストがない:ユーザー ID がスコープ内にある時に "User not found"
  • 例外タイプだけで冗長:log.error("NullPointerException", e) は何も追加しません
  • 確立されたパターンと比較してケーシングまたは時制が矛盾している
  • 機密データを公開している:パスワード、トークン、PII がログメッセージ内
# 曖昧なメッセージ (Python)
grep -rn "logger\.\w\+(['\"].\{1,20\}['\"])" --include="*.py" . | \
  grep -i '"error"\|"fail"\|"exception"\|"done"\|"ok"\|"success"\|"null"'

# 非常に短いメッセージ (Java)
grep -rn 'log\.\w\+("\w\{1,10\}")' --include="*.java" . | head -20

メッセージ品質の問題があるファイルについて、周囲のコードを読んで、関連するコンテキスト変数を含む、より良いメッセージを提案します。

3e. 確立されたパターンとの矛盾

各ログ呼び出しをフェーズ 2 で確立されたパターンと比較します:

  • ノルムと異なる方法でロガーをインスタンス化
  • メッセージケーシングまたは動詞時制が異なる
  • 構造化フィールドがある場所では使用されているが、他の場所では使用されていない
  • 必須フィールド(フェーズ 2 から)が欠落している — 例:request_id を省略するリクエストハンドラー内のログ、または error/err を省略する WARN/ERROR ログ

フェーズ 4:レポートを出力

すべての発見を単一のレポートにグループ化します。順序:削除 → ログ欠落 → 不適切なレベル → 不適切なメッセージ → 矛盾

削除を最初に配置してください。機密データがログに含まれることは即座のセキュリティリスク — 他の改善に対応する前に対処する必要があります。

各セクション内で、ファイルごとに順序付けます。各発見には、ファイルパス、行番号、現在のコード(存在する場合)、および具体的な推奨される改善を含めます。

このフォーマットを使用します:

## ログ改善レポート

### 確立されたパターン
[検出または提案されたパターンをここに記述します。提案の場合、「⚡ 一貫したパターンが見つかりません — 以下を提案:」で前置きしてください]

例:
  logger.info("order.placed", order_id=order_id, amount=amount)
  # noun.verb メッセージ、構造化キーワード引数、モジュールレベルロガー

---

### 1. 削除   (N 件の発見)

**src/auth/login.py:14** — ログ内の機密フィールド
  現在:`logger.info("login success", extra={"user_id": user.id, "password": password})`
  削除:extra dict から `password` フィールドを削除
  理由:ログ内のパスワードはプレーンテキストで保存され、ログアクセス権を持つ誰もが、ログ集約サービスを含めてアクセスできます

**src/debug/util.py:8** — デバッグアーティファクト
  現在:`print(f"Login attempt for {username}")`
  アクション:`logger.info("auth.login_attempt", username=username)` で置き換えるか、削除
  理由:print() はログフレームワークをバイパスし、本番環境でフィルター処理または沈黙化できません

---

### 2. ログステートメントの欠落   (N 件の発見)

**src/payments/processor.py:88** — ログのないエラーパス
  コンテキスト:`except StripeError as e:`
  追加:`logger.error("payment.charge_failed", order_id=order_id, error=str(e))`
  理由:stripe の失敗はサイレント — 請求が失敗するとオペレーターは可視性がありません

**src/jobs/email_sender.py:34** — 失敗ログのない外部呼び出し
  コンテキスト:`response = smtp.send(msg)`
  追加(失敗時):`logger.error("email.send_failed", recipient=msg.to, error=str(e))`

---

### 3. 不適切なログレベル   (N 件の発見)

**src/auth/login.py:52** — エラーが WARNING としてログされている
  現在:`logger.warning("Login failed for user %s", user_id)`
  提案:`logger.error("auth.login_failed", user_id=user_id)`
  理由:ログイン試行失敗はアラート価値のあるエラーです、単なる警告ではありません

**src/cache/client.py:19** — 厳密なループで DEBUG がログスパムを生成
  現在:`logger.debug("Cache miss for key %s", key)`(すべてのリクエストで呼び出される)
  提案:削除するか、機能フラグで制御、代わりに集約メトリックを出力

---

### 4. メッセージ品質が低い   (N 件の発見)

**src/api/users.py:101**
  現在:`logger.error("Error")`
  提案:`logger.error("user.fetch_failed", user_id=user_id, error=str(e))`
  理由:「Error」は対応不可能 — どのユーザー、どのオペレーション、何が問題か?

**src/db/connection.py:14**
  現在:`logger.info("Connected")`
  提案:`logger.info("db.connected", host=host, port=port, database=db_name)`
  理由:環境全体での接続問題のデバッグに必要なコンテキスト

---

### 5. 矛盾   (N 件の発見)

**src/orders/service.py:67** — 通常は構造化される非構造化メッセージ
  現在:`logger.info(f"Order {order_id} placed by {user_id}")`
  提案:`logger.info("order.placed", order_id=order_id, user_id=user_id)`

---

### 概要

| カテゴリ           | 件数 |
|--------------------|------|
| 削除               |    2 |
| ログステートメント欠落 |    4 |
| 不適切なログレベル |    3 |
| メッセージ品質が低い |    6 |
| 矛盾               |    5 |
| **合計**           |**20** |

### 推奨される次のステップ
- 「削除」に即座に対応してください — ログ内の機密データはセキュリティインシデント寸前です。
- 次に「ログステートメント欠落」に対応してください — サイレントエラーパスは最大の運用上リスクです。
- 今後、すべての新しいログ呼び出しに確立されたパターンを適用してください。
- CI でログレベル規律を実施するためのリンティングルールの追加を検討してください。

セクションで問題が見つからない場合は、「問題は見つかりません」と書く代わりに、そのセクション全体を省略してください。

コードベースの総ログ呼び出しが 5 個未満の場合、パターン提案で始まり、修正対象ではなくログを追加する場所に焦点を当てたレポートにしてください。

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
dan323
リポジトリ
dan323/easier-life-skills
ライセンス
MIT
最終更新
2026/5/11

Source: https://github.com/dan323/easier-life-skills / ライセンス: MIT

本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: dan323 · dan323/easier-life-skills · ライセンス: MIT