log-doctor
通用、可跨專案使用的 log skill。兩個層面、兩種輸入,選對模式再做事:
- 模式 A — 審查 codebase log:輸入是「原始碼」。判斷
log.*()呼叫合不合規範、夠不夠除錯。 - 模式 B — 分析 log 檔案:輸入是「執行時產出的 log」。重建流程、找異常。
模式判定
- 給
.log路徑、貼 log 內容、問「這次跑出什麼問題/卡在哪」→ 模式 B。 - 問「log 寫得對不對 / PR 的 log 覆蓋夠不夠 / 這段該不該 log」→ 模式 A。
- 不確定就問:「你要審查原始碼的 log 寫法,還是分析跑出來的 log 檔?」
規則分層(兩模式共用)
log-doctor 自帶通用基準 references/generic-rules.md,並在執行時偵測專案自己的 log 規範疊加上去:
- 依序找專案規範檔(找到就用,以它為現行硬規則):
- 使用者明確指定的路徑
.knowledge/**/logging*.md、docs/**/logging*.md、**/logging-policy.md- 專案
CLAUDE.md內的 logging 段落
- 有專案規範 → 它是硬規則,
generic-rules.md降為建議升級維度。 - 沒有專案規範 →
generic-rules.md即為硬規則。 - 衝突時專案優先,不要混血(把差異列出讓人決定,別自行折衷)。具體語法(JSON /
%skey=value /[STATE]前綴等)一律以專案規範為準。
模式 A — 審查 codebase log
範圍預設 git diff(適合 PR review / commit 前審查;使用者要求才掃全 codebase)。
Step 1: AST 事實抽取(零 token)
跑預處理腳本,取得每個函式的結構化摘要(I/O 呼叫、log 呼叫含 level、except block 狀態):
python <skill-dir>/scripts/extract_log_facts.py <repo_root> # diff mode (預設)
python <skill-dir>/scripts/extract_log_facts.py <repo_root> --files <paths> # 指定檔案
python <skill-dir>/scripts/extract_log_facts.py <repo_root> --all # 全量掃(使用者要求時)
腳本輸出純事實,不下判斷。每個函式列出:
- I/O 呼叫:哪些外部操作(camera、serial、HTTP、MQTT、sink 等),含行號
- Log 呼叫:每筆的 level + 行號 + 是否在 except block 內
- Except block:行號、exception types、body 摘要(pass/raise/return None/other)、有無 reraise、有無 log
無改動且未指定檔案 → 回報無變更並停止。
Step 2: 載入規範
依「規則分層」載入專案 log 規範(見上方規則分層段落)。
Step 3: 摘要判讀(少量 token)
拿 Step 1 的事實摘要 + Step 2 的規範,逐函式判讀,不讀原始碼:
- 覆蓋率:有 I/O 呼叫但 Log 為 (none) → 缺失。有 except block 且
no log+reraise=False→ 靜默吞錯。 - Level 合規:比對規範的 level 表。例:「可恢復的失敗 = WARNING」但 log 是 info/debug → level 不當。「關鍵業務事件 = INFO」但 log 是 debug → 不可見。
- 格式初篩:從摘要無法判斷格式,標記需要看原文的函式。
Step 4: 精讀可疑函式(僅必要時)
只對 Step 3 標記的函式讀原始碼(用 Read tool 帶 offset/limit 只讀該函式),做最終確認:
- log message 格式是否符合規範(
%slazy formatting、[STATE]前綴、key=value) - except block 的具體語境(是否為已知可接受的 trivial fallback)
- 流程級檢查:這段改動的失敗路徑、狀態轉換、決策點(reason)有沒有覆蓋
Step 5: 產出報告
分兩類:
- [必修] 違反現行硬規則:
file:line+ 規則 + 問題 + 可貼上的修正。 - [建議] 可升級但需確認:同格式,標明是規範升級建議。
預設只報告。要不要套修正由使用者決定;要改就一次改完再 commit。
不要因「程式現在這樣寫」反推需求去固定它。規範來源是規則檔,不是既有實作。
模式 B — 分析 log 檔案
- 專案設定優先於參數:專案專屬設定(格式、correlation、lifecycle、stage、gap 門檻)住在
<project-root>/.knowledge/log-doctor.yaml(專案既定內容歸 .knowledge/;無 .knowledge/ 的專案放專案根)。解析器從 logfile 目錄向上自動偵測,每層先查.knowledge/再查該層本身。首次使用該專案且找不到設定檔時,先產生模板再依 log 樣貌填寫:
填寫前先python <skill-dir>/scripts/parse_log.py --init <project-root>/.knowledgehead看幾行 log 推斷格式與 correlation key。CLI 旗標僅作臨時覆寫用,不要靠一長串旗標工作。 - 跑確定性解析器(別用模型做機械解析 — 能用 code 就用 code):
自動輸出:level 分佈、WARN/ERROR 清單、traceback 歸戶、重複噪音樣態、foreign 行(不符主格式但像另一個 logger 的輸出,如 OpenCV/FFmpeg 直寫 stderr 的 WARN — 不會被靜默併進 traceback)、時間斷檔(gap ≥python <skill-dir>/scripts/parse_log.py <logfile-or-glob> [more...]gap_seconds,重啟/斷線的訊號)、生命週期(孤兒/非 ok)與 per-stage 耗時統計(stages設定)。多檔/glob 一次跑會附 fleet 匯總列。 - 模型只做判讀:依摘要回答——流程在哪步中斷(看孤兒的最後事件)、失敗根因(讀對應 traceback)、單點還是系統性(problem 是否集中同一 logger/狀態)、gap 與 foreign WARN 對得上什麼事件(重啟?斷流?)。引用具體時間戳與 id,不要泛談。注意 stage 耗時的語意:stage 結束於下一個 stage 開始或 done 記錄,最後一個 stage 會含 emit/上傳時間。
- 只有片段沒檔案 → 存到暫存檔再餵解析器,或直接依格式判讀。
解析器只做機械解析,不判斷 log 品質;品質問題屬模式 A。若發現 log 資訊不足以除錯(失敗只有「failed」沒原因),回報並建議切模式 A 補強。