OCR 內建一流 OpenTelemetry 支援。啟用後,每次評審產出結構化 span、metric、event——足以回答「agent 把時間花在哪?」「各模型成本如何?」「這次為何失敗?」。
| Exporter | 何時使用 |
|---|---|
console | 個人使用 / 除錯。span 格式化印到 stdout。 |
otlp | 系統整合。送任何 OTLP 相容 collector(Jaeger、Tempo、OTel Collector、Datadog…)。 |
# config 方式
ocr config set telemetry.enabled true
ocr config set telemetry.exporter otlp
ocr config set telemetry.otlp_endpoint localhost:4317
# 環境變數方式
export OCR_ENABLE_TELEMETRY=1
export OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317 # 同時強制 exporter=otlp
export OTEL_SERVICE_NAME=open-code-review
review.run
├── diff.parse
├── event.review.started
├── subtask.execute.<file1>
│ ├── event.plan.skipped
│ ├── event.token.threshold.exceeded
│ └── event.subtask.error
├── subtask.execute.<file2>
└── …
LLM 往返與工具執行不作為獨立 span——只出現在 metric。決策點事件是短生命週期的 event.<name> span。
| Metric | 型別 | 標籤 |
|---|---|---|
ocr.review.duration_seconds | histogram | — |
ocr.files_reviewed_total | counter | — |
ocr.comments_generated_total | counter | — |
ocr.llm.requests_total | counter | model、status |
ocr.llm.tokens_used | counter | model、type |
ocr.tool.calls_total | counter | tool.name、status |
遙測導出 LLM 流量的形狀(計數、時長、狀態),但絕不導出實際 prompt 或回應。OCR 不嘗試把 LLM 訊息內容附加到 span 或 event。
content_logging config key 與 OCR_CONTENT_LOGGING=1 已接入配置層,但目前不控制任何發送 prompt 內容的程式路徑——視為保留位。
~/.opencodereview/ 下,絕不發往 collector。~/.opencodereview/config.json 的 telemetry.*。- name: Code review
env:
OCR_LLM_URL: ${{ secrets.OCR_LLM_URL }}
OCR_LLM_TOKEN: ${{ secrets.OCR_LLM_TOKEN }}
OCR_LLM_MODEL: claude-opus-4-6
OCR_ENABLE_TELEMETRY: "1"
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ vars.OTEL_COLLECTOR_URL }}
OTEL_SERVICE_NAME: open-code-review-ci
run: ocr review --from origin/main --to HEAD --audience agent
| 症狀 | 可能原因 |
|---|---|
| 什麼都沒匯出 | 預設關閉——沒設 OCR_ENABLE_TELEMETRY / telemetry.enabled |
| OTLP 本地可用、生產失敗 | OCR 目前僅實作 OTLP/gRPC;http/protobuf 被接受但未接入 |
| span 缺 prompt | OCR 絕不把 prompt 內容附加到遙測——用 viewer 檢查轉錄 |
三個原因:① 隱私(不是每個人都想把執行遙測送到外部)② 效能(OTLP exporter 有網路開銷)③ 依賴(需要 collector)。所以預設關閉,要主動打開。
每個評審的 span 樹長這樣:
review.run
├── diff.parse ← diff 解析耗時
├── event.review.started ← 開始事件
├── subtask.execute.file1 ← 每個檔案一個
│ ├── event.plan.skipped ← plan 跳過(小 diff)
│ └── ...
└── subtask.execute.file2
LLM 往返不作為獨立 span——只出現在 ocr.llm.requests_total metric。所以看 LLM 延遲要看 metric,不是 span。
遙測導出的是形狀(計數、時長、狀態),不是內容(prompt、response、diff)。content_logging config key 已存在但目前不控制任何發送 prompt 內容的程式路徑——視為保留位。要看 prompt 內容?用 Session Viewer 讀本地 JSONL。
延伸閱讀:設定 · 架構 · Session Viewer
你的 CI 每天跑 200+ 次 OCR 評審,你無法追蹤「評審健不健康」。你要把遙測送到 Tempo(trace)+ Prometheus(metric),在 Grafana 上看到:評審時長、成功率、模型成本、最常出錯的工具。
# otel-collector-config.yaml
receivers:
otlp:
protocols:
grpc: # OCR 實作的是 OTLP/gRPC
exporters:
otlp/tempo:
endpoint: tempo:4317
prometheus:
endpoint: "0.0.0.0:8889"
service:
pipelines:
traces: { receivers: [otlp], exporters: [otlp/tempo] }
metrics: { receivers: [otlp], exporters: [prometheus] }
env:
OCR_ENABLE_TELEMETRY: "1"
OTEL_EXPORTER_OTLP_ENDPOINT: collector:4317
OTEL_SERVICE_NAME: open-code-review-ci
run: ocr review --from origin/main --to HEAD --audience agent
# 面板 1: 評審時長 (histogram)
sum(rate(ocr_review_duration_seconds_sum[5m])) /
sum(rate(ocr_review_duration_seconds_count[5m]))
# 面板 2: 模型成本 (tokens by type)
sum by (model, type) (rate(ocr_llm_tokens_used_total[5m]))
# 面板 3: 工具錯誤率
sum(rate(ocr_tool_calls_total{status="error"}[5m])) /
sum(rate(ocr_tool_calls_total[5m]))
在 Grafana 切到 Tempo datasource,搜 review.run,點開失敗的 trace,看哪個 subtask.execute.<file> 掛掉。
「評審本身」也是一個要監控的系統。用 OCR_ENABLE_TELEMETRY + collector 把「形狀」(時長、計數、狀態)送出——不含任何 prompt 內容,符合隱私要求。選 Tempo + Prometheus 是因為 OTLP/gRPC 是 OCR 唯一實作的協定,本地驗證用 console exporter、上線用 OTLP 是最低摩擦路徑。
預期產出
Grafana 顯示:
評審平均時長 42s(昨天 38s → 有漂移,追查發現 concurrency 撞 rate limit)
模型成本: input 68% / output 32%
工具錯誤率 3.1% → 集中在 code_search(repo 太大?)
失敗 trace: subtask.execute.auth.go → context deadline exceeded
官方文件明確:OTLP/gRPC 已實作;http/protobuf 被接受但未接入。也就是說:OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318(HTTP 埠)或 --otlp-http 風格設定會被「接受」(不報錯)但不會真的送資料。本機測試用 console exporter 可驗證 span 產生;要送 collector 務必確認走 4317(gRPC)。
# 你設了:
export OCR_ENABLE_TELEMETRY=1
export OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318 # ← HTTP 埠
export OTEL_SERVICE_NAME=open-code-review
# OCR 不報錯、正常跑完、exit 0 —— 但 Grafana 一片空白
# 原因: 4318 是 OTLP/HTTP 埠;OCR 只實作 gRPC (4317),HTTP 被接受但未接入
「不報錯 + 沒資料」是最難 debug 的組合。防禦:① 本機先跑一次 OCR_ENABLE_TELEMETRY=1(exporter 預設 console)確認 span 有印出;② 確認 endpoint 走 collector:4317(gRPC);③ 在 collector 側開 debug log 確認有 receiver 收到。
| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
| Grafana 完全沒資料 | 遙測沒啟用,或走錯 OTLP 埠(HTTP 4318 vs gRPC 4317) | 設 OCR_ENABLE_TELEMETRY=1;確認 endpoint 是 gRPC 埠 |
| 本機 console 有 span、collector 沒有 | exporter 被 env 設成 otlp,但 endpoint 不對 | 確認 OTEL_EXPORTER_OTLP_ENDPOINT 指向 collector 的 4317 |
| trace 有、metric 沒有 | collector pipeline 沒設 metrics exporter | 在 collector config 加 prometheus exporter 進 metrics pipeline |
| 看不到 LLM 延遲 | LLM 往返不作為獨立 span,只在 metric | 看 ocr_llm_requests_total / ocr_llm_tokens_used,不看 span |
| 想找「哪個工具最會失敗」 | — | 用 ocr_tool_calls_total{status="error"} 依 tool.name 分組 |