把 Claude Code 接上 OpenTelemetry:你團隊每天燒多少 token,其實沒人知道
月底,主管在 Slack 丟一句:這個月團隊用 Claude Code 花了多少?哪個專案最燒?
你打開 /usage。上面有數字,很漂亮,但那是你這台筆電、這個帳號、這段期間的用量。團隊有十二個人。
兩條你大概已經試過的路
第一條是去看帳單。帳單給你一個總額,準確到分。它不會告訴你這筆錢是花在那個跑了三天的重構上,還是花在有人拿它問了兩百次「幫我看一下這段 code」。一個總數等於沒有分佈,你拿它做不了任何決定。
第二條是叫大家自己回報。這條路的壽命通常是一週。第二週開始有人忘記填,第三週表格就變成考古遺址。
兩條路都堵住,是因為你想量的東西根本沒有量測點。家裡的電費單也是這樣,只有一個總金額,你懷疑是烘衣機在吃電,但手上沒有工具能驗證,只能靠感覺吵架。/usage 是那張帳單,接下來要裝的是插座上的分表。
一個環境變數,五分鐘看到數字
Claude Code 內建 OpenTelemetry 匯出,預設是關的。開它需要兩件事,只做一件不會有任何反應。
第一件是總開關:
1 | export CLAUDE_CODE_ENABLE_TELEMETRY=1 |
第二件是告訴它資料要送去哪。想先看看長什麼樣,直接吐到 console 最快:
1 | export OTEL_METRICS_EXPORTER=console |
第二行很關鍵。OTEL_METRIC_EXPORT_INTERVAL 預設是 60000,也就是一分鐘才吐一次。你不改它,開好之後會盯著一片空白的終端機懷疑自己是不是設錯了,然後在第 59 秒放棄。除錯階段調成 5 秒,之後再調回去。
Exporter 這裡有個不對稱要記住:metrics 可以選 console、otlp、prometheus、none,但 logs 跟 traces 只有 console、otlp、none。只有 metrics 吃 prometheus。 想把 event 也送進 Prometheus 的話,得先過一手 OTel Collector。
要送多個地方,用逗號串:
1 | export OTEL_METRICS_EXPORTER=console,otlp |
它到底會吐出什麼
Metrics 有八個:
1 | claude_code.session.count # 開了幾次 session |
cost.usage 跟 token.usage 是回答開場那個問題的主力。code_edit_tool.decision 比較少人注意,但它其實是最有意思的一個:它記錄每次 Claude 想改檔案時,人類到底按了同意還是拒絕。這個比率如果一直很低,代表你們的 CLAUDE.md 沒寫好,模型一直在提議大家不想要的東西。花掉的 token 是成本,被拒絕的提議是浪費,這是兩件事。
除了 metrics 還有十五個 log event,涵蓋 user_prompt、assistant_response、tool_result、api_request、api_error、api_refusal、tool_decision、mcp_server_connection 這些,全部帶 claude_code. 前綴。metrics 給你趨勢,events 給你單一事件的細節,兩邊的用途不一樣。
先別急著全開,這裡有個坑
上面那些 event 名稱看起來很誘人,尤其是 user_prompt 跟 assistant_response。你可能會想,全開吧,資料越多越好。
先等一下。
預設情況下,OTEL_LOG_USER_PROMPTS 是關的,只記錄「有這個事件發生」,不記內容。OTEL_LOG_TOOL_DETAILS、OTEL_LOG_TOOL_CONTENT、OTEL_LOG_RAW_API_BODIES 也全都預設關閉。這個設計是刻意的:prompt 裡面常常有客戶名字、內部路徑、貼進去 debug 的 API key。
然後是那個坑。v2.1.193 新增了 claude_code.assistant_response 這個 event,內容是模型回覆的全文。它的行為是這樣:如果你沒有明確設定 OTEL_LOG_ASSISTANT_RESPONSES,它會跟隨 OTEL_LOG_USER_PROMPTS 的設定。
翻成白話:一個原本就有開 prompt 記錄的部署,升級到 v2.1.193 之後,會在沒有人做任何動作的情況下,自動開始把模型回覆的全文也收進你的 log 後端。CHANGELOG 自己寫得很清楚,要維持只記 prompt,得明確設定:
1 | export OTEL_LOG_ASSISTANT_RESPONSES=0 |
這種「預設值繼承另一個開關」的設計在功能上很合理,在資安上就是一個安靜的擴權。如果你的公司有在稽核資料存放在哪、誰看得到,這就是那種事後被問「這批資料什麼時候開始收的、誰核准的」會答不出來的東西。
順帶一提,內容類欄位有截斷上限,由 CLAUDE_CODE_OTEL_CONTENT_MAX_LENGTH 控制,預設 61440,也就是 60 KB。這個變數是 v2.1.214 才加的,在那之前上限寫死。
接 Prometheus 之前,先關掉兩個標籤
想把 metrics 餵進 Prometheus,有個東西一定要先處理,不然你會親手做出一顆定時炸彈。
Claude Code 預設會在每個 metric datapoint 上掛 session.id 跟 user.account_uuid 這兩個屬性。對 log 系統來說這很棒,你可以精準追到單一 session。對 Prometheus 來說這是災難:每一個 session ID 都會生出一條全新的時間序列。一個十二人團隊一天開幾百個 session,一個月就是上萬條序列,全部是查完就再也用不到的死資料。這就是 cardinality 爆炸。
把它們關掉:
1 | export OTEL_METRICS_INCLUDE_SESSION_ID=false |
另外三個相關開關的預設值分別是:OTEL_METRICS_INCLUDE_VERSION 預設 false、OTEL_METRICS_INCLUDE_ENTRYPOINT 預設 false、OTEL_METRICS_INCLUDE_RESOURCE_ATTRIBUTES 預設 true。前兩個是低基數的,要看版本分佈或進入點分佈的話開起來很安全。
還有一個容易漏的:OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE 預設是 delta,但 Prometheus 那套生態通常吃 cumulative。走 Collector 轉一手的話記得對齊,不然你會看到一堆歸零的曲線然後懷疑人生。
團隊版:不要叫每個人自己設環境變數
到這裡都還是個人玩法。回到開場那個問題,你要的是十二個人的資料,那就不能靠每個人自己在 .zshrc 裡加東西。
用 managed settings 集中派發:
1 | { |
然後用 resource attributes 切維度,這樣才答得出「哪個專案最燒」:
1 | export OTEL_RESOURCE_ATTRIBUTES="department=engineering,team.id=platform,cost_center=eng-123" |
這些值會變成 datapoint 上的 label,之後就能照部門、團隊、成本中心分組。這是回答「哪個專案最燒」的那一塊拼圖。
如果你們有在用 Workflow,v2.1.202 之後 metrics 會多帶 workflow.run_id 跟 workflow.name,可以把一次 workflow run 裡所有 agent 的活動整包重建出來。一次跑二十個 subagent 的任務到底花多少錢,這個屬性讓它從猜測變成可查。
還沒解掉的部分
誠實講幾件事。
Traces 還在 beta,要另外開 CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1。我沒有在正式環境跑過 traces,這段是照文件寫的。
官方沒有提供現成的 Grafana dashboard,也沒給範例 PromQL。上面那八個 metric 名稱是官方的,怎麼組成好看的圖表是你自己的工程,這部分要自己刻。
還有幾個近期的修正值得知道,免得你踩到已經被修好的洞:v2.1.212 修掉 OTel HTTP 匯出被 Azure Monitor 這類端點以 411 或 400 拒絕的問題,根因是 chunked transfer encoding;v2.1.216 修掉 OTEL_METRICS_EXPORTER=prometheus 端點吐出無效 # UNIT 行;同一版也修掉一個統計誤差,權限提示失敗以前會被算成「使用者拒絕」,現在不會了。如果你的 Claude Code 版本比這些舊,看到怪數字先升版再說。
回到月底那句話
現在主管再問一次那個問題,你的處理方式會變成這樣:打開 Grafana,claude_code.cost.usage 按 team.id 分組,時間軸拉到本月,截圖貼回 Slack。旁邊順便放一張 code_edit_tool.decision 的核准率,因為那張圖能講的事情通常比成本那張多。
不過在開之前,先花五分鐘決定三件事:OTEL_LOG_USER_PROMPTS 要不要開、OTEL_LOG_ASSISTANT_RESPONSES 要不要顯式關掉、以及 session.id 那個標籤要不要進 Prometheus。量測本身沒有風險,量測的時候順手把不該存的東西一起存下來才有,而這三題答錯就是那個情況。
參考來源:Monitoring usage - Claude Code Docs、anthropics/claude-code CHANGELOG(v2.1.193 / 202 / 212 / 214 / 216 條目)。文中設定值以官方文件為準;traces beta 與 Grafana 儀表板部分我尚未實際部署過,已在文中標注。


























































































































































