Claude CodeのOpenTelemetryで利用量とコストを可視化
Claude CodeのOpenTelemetry連携で利用量・コスト・監査ログを可視化する設定手順と、アップグレード時にassistant_responseが意図せず記録される落とし穴をまとめます。
はじめに
チーム全体のClaude Code利用状況は、開発者一人ひとりが/costコマンドを個別に確認するだけでは全体像が見えてきません。OpenTelemetry(OTel)経由でメトリクスとイベントを外部バックエンドに送れば、誰がどれだけ使い、コストがどこに寄っているかをダッシュボード上で追えるようになります。
前提条件は次の3つです。
| 項目 | 必要な状態 |
|---|---|
| Claude Code | 必要な状態制約なし(バージョン別の差分は本文で明記) |
| バックエンド | 必要な状態OTLP受信可能な収集基盤(Prometheus、Honeycomb、Datadog、Grafana Cloud等) |
| 環境変数の設定権限 | 必要な状態シェル、または管理設定(managed settings)ファイルへの書き込み権限 |
管理者は組織全体の設定をmanaged settingsファイル経由で強制でき、開発者個人が任意のエンドポイントへ向け先を変えることを防げます。
ステップ1: テレメトリを有効にしてエクスポート先を設定する
最小構成は環境変数5つです。
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317CLAUDE_CODE_ENABLE_TELEMETRYが有効化の必須スイッチで、これだけではどこにも送られません。メトリクスはOTEL_METRICS_EXPORTER、イベント(ログ)はOTEL_LOGS_EXPORTERと、送りたい信号ごとにエクスポーターを指定します。どちらもnoneを指定すれば個別に無効化できるので、メトリクスだけ欲しい場合はログ側をnoneにしておくと送信量を絞れます。
エクスポート間隔にも既定値があります。メトリクスはOTEL_METRIC_EXPORT_INTERVALが既定60000ms(60秒)、イベントはOTEL_LOGS_EXPORT_INTERVALが既定5000ms(5秒)です。設定確認中はメトリクスの反映を待つ時間が長く感じられるため、動作確認時だけ値を短く設定して間隔を詰めておくと反応を確かめやすくなります。
設定が届いているかどうかは2つのシグナルで確認できます。claude_code.session.countメトリクスはセッション開始時に発行されます。claude_code.user_promptイベントはプロンプト送信時に発行されます。どちらかがバックエンドに届いていれば成功です。何も届かない場合はclaude --debugでOTelのエクスポートエラーをデバッグログから探します。
管理設定でエンドポイントを固定している組織では、個々の開発者がシェルで別のエンドポイントを指定しても上書きできません。汎用のOTEL_EXPORTER_OTLP_ENDPOINTを管理設定側で指定すると、信号ごとの個別エンドポイント指定がまとめて無効化される仕組みです。テレメトリの送信先を1か所に固定したい組織向けの防御になっています。開発者から見ると「設定したのに反映されない」という形で気づくため、まず管理設定の内容を確認するのが早道です。
ステップ2: 利用量とコストのメトリクスを読む
Claude Codeが発行する主なメトリクスは8種類です。
| メトリクス | 何が分かるか |
|---|---|
claude_code.session.count | 何が分かるかセッション開始数(採用率の推移) |
claude_code.token.usage | 何が分かるか入力/出力/キャッシュ別のトークン消費量 |
claude_code.cost.usage | 何が分かるかセッションのコスト(USD、概算値) |
claude_code.lines_of_code.count | 何が分かるか追加/削除された行数 |
claude_code.pull_request.count | 何が分かるか作成されたPR/MR数 |
claude_code.commit.count | 何が分かるか作成されたgitコミット数 |
claude_code.code_edit_tool.decision | 何が分かるかコード編集ツールの提案が承認/却下された件数 |
claude_code.active_time.total | 何が分かるか実際に活動していた時間の合計 |
claude_code.cost.usageとclaude_code.token.usageはskill.name・plugin.name・agent.nameの属性を持ちます。どのスキルやサブエージェントがコストを押し上げているかまで分解できるということです。ただしコストメトリクスはあくまで概算です。正式な請求額は、実際に契約しているプロバイダー(Claude Console、Amazon Bedrock、Google CloudのAgent Platformなど)側の数字を正とします。契約形態別の料金の考え方はClaude Codeの料金ガイドにまとめています。
コスト急増や異常なトークン消費を早期に検知したい場合は、標準属性でセグメント分割してアラートを組むのが定石です。使える属性はmodelやquery_source(main/subagent/auxiliary)などです。モデル別のコミット数まで分解したい場合は、session.idでトークンやコストのメトリクスと突き合わせます。その上でquery_sourceがmainの行だけに絞り込みます。サブエージェントやauxiliaryのリクエストをそのまま合算すると、コミットしていないモデルに手柄を誤帰属してしまいます。
ステップ3: 監査・SIEM向けにイベントを設定する
OpenTelemetryのイベント(ログ)は、Claude Codeの操作を誰が行ったかまで追跡できる監査データです。認証済みのユーザー情報(user.email・user.account_uuid・organization.id)が標準属性として各イベントに付きます。そのためBashコマンド・ファイル編集・MCP呼び出しは、すべて実行した開発者本人に紐づきます。組織のセキュリティ設計全体との位置付けはClaude Codeセキュリティ・権限ガイドも参考にしてください。
MCPサーバーの呼び出し詳細まで監査したい場合は、OTEL_LOG_TOOL_DETAILS=1を追加します。これを設定するとtool_resultとtool_decisionイベントにサーバー名・ツール名・呼び出し引数が乗るようになります。設定しない場合はツール名が"mcp_tool"という文字列に丸められ、引数も落とされます。SIEMへ転送する場合はOTEL_EXPORTER_OTLP_LOGS_ENDPOINTを専用のOTLP受信エンドポイントに向けるだけで済みます。メトリクスとは別系統でイベントだけを送ることもできます。
直接APIキーで認証している場合や、Amazon Bedrock・Google CloudのAgent Platform経由の場合は事情が異なります。Claudeアカウントに紐づく識別情報がセッションに存在しないため、user.idとsession.idしか埋まりません。ユーザー単位の追跡が必要な組織では、OTEL_RESOURCE_ATTRIBUTESでユーザー識別子を自前で付与する運用が案内されています。
トレース(ベータ)でリクエストの流れを追う
メトリクスとイベントに加えて、分散トレーシングもベータで提供されています。1つのユーザープロンプトが引き起こしたAPIリクエストとツール実行を、1本のトレースとしてつなげて可視化する機能です。既定では無効です。CLAUDE_CODE_ENABLE_TELEMETRY=1に加えてCLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1を設定します。あとはOTEL_TRACES_EXPORTERで送信先を選ぶだけです。
エンドポイントやプロトコル、認証ヘッダーの指定はメトリクス・イベントと共通のOTLP設定を使い回せます。特定のツール呼び出しがどこで時間を食っているか、どのAPIリクエストがどのプロンプトに紐づくかを1リクエスト単位で追いたい場合に向いており、集計値だけでは見えないボトルネックの特定に役立ちます。常時有効にすると送信量が増えるため、調査したい期間だけ絞って有効化する運用が現実的です。
OTEL_LOG_ASSISTANT_RESPONSESを設定しないと何が起きるか
ここが実務で最も踏みやすい落とし穴です。v2.1.193でassistant_responseイベントが追加され、Claudeの応答テキストをログに残せるようになりました。この応答テキストは既定で<REDACTED>に伏せられ、OTEL_LOG_ASSISTANT_RESPONSES=1を明示しない限り中身は出ません。
問題は未設定時の挙動です。OTEL_LOG_ASSISTANT_RESPONSESを一度も設定していない環境では、値はOTEL_LOG_USER_PROMPTSの設定に連動します。プロンプトのロギングだけを目的に、以前からOTEL_LOG_USER_PROMPTS=1にしていた組織があるとします。この組織がClaude Codeをv2.1.193以降にアップグレードした瞬間、設定を何も変えていないのに応答テキストの記録が新たに始まります。プロンプトだけ集めるつもりが、Claudeの出力内容まで一緒にログ基盤へ流れ込む形です。
応答だけを確実に伏せたい場合は、OTEL_LOG_ASSISTANT_RESPONSES=0を明示的に設定します。これでプロンプトのログは維持したまま、応答テキストだけを<REDACTED>のままにできます。応答内容には機密情報や個人情報が含まれる可能性があるため、ログ基盤へのアクセス権限を持つ人の範囲を、プロンプトロギングを有効化した時点で見直しておくと安全です。この機能自体の変更点はv2.1.193のリリースノートにもまとまっています。
コスト分析でよくあるつまずき
メトリクスは届くがコストの数字が合わない場合、claude_code.cost.usageはあくまで概算である点を思い出してください。正式な請求額の突合には、契約しているプロバイダーのコンソール側の数字を使います。
Prometheusでスクレイプがエラーになる場合、OTEL_METRICS_EXPORTERの指定を確認します。prometheus単体指定かotlp,prometheusのような複数指定かで挙動が変わるためです。単体指定時はUSD・tokens・秒の単位表記が、Prometheusのテキスト形式として妥当であり続けるため自動的に省かれ、複数指定時は単位が残ります(なお# UNIT行によるOpenMetrics形式での単位表記はv2.1.216以前の挙動です)。
マネージド設定でエンドポイントを固定したのに開発者側の値が効いてしまう場合は、固定しているのがどの粒度の変数かを確認します。汎用のOTEL_EXPORTER_OTLP_ENDPOINTを管理設定側で設定すると、信号別のエンドポイント上書きはまとめて無効化されます。一方OTEL_METRICS_EXPORTERのようなエクスポーター選択自体は個別キーの優先順位に従います。無効化させたいなら、管理設定側でも明示的に指定しておく必要があります。
まとめ
利用量とコストの可視化だけが目的なら、OTEL_METRICS_EXPORTERとエンドポイントの設定だけで足ります。監査やSIEM連携まで見据えるなら、OTEL_LOGS_EXPORTERとユーザー識別情報の設計も合わせて検討する価値があります。既にOTEL_LOG_USER_PROMPTS=1で運用している環境をアップグレードする際は、OTEL_LOG_ASSISTANT_RESPONSESを明示しておくことが唯一の注意点です。
メトリクス・イベント・トレースは別々のエクスポーターとエンドポイントを持てます。まずはコスト可視化のためのメトリクスだけを小さく始め、必要に応じて監査用のイベント、調査用のトレースへと段階的に広げる進め方が扱いやすいはずです。
よくある質問
assistant_responseイベントはv2.1.193より前のバージョンでも出ますか
出ません。この機能はClaude Code v2.1.193以降が必要です。
コンテンツの切り詰め上限は変更できますか
できます。CLAUDE_CODE_OTEL_CONTENT_MAX_LENGTHで応答テキストやツール内容などコンテンツ系属性の切り詰め上限を調整できます(既定60KB)。バックエンドが受け付ける属性値の上限に合わせて調整します。
ツールの呼び出しパラメータまで見るには何を設定すればよいですか
OTEL_LOG_TOOL_DETAILS=1を設定します。Bashコマンドの実行内容やMCPサーバー・ツール名、スキル名などがtool_result・tool_decisionイベントに乗るようになります。
Bashツールから起動した別のOpenTelemetry対応アプリは、Claude Code自身のエクスポート設定を引き継ぎますか
引き継ぎません。Claude CodeはBashツールやフック、MCPサーバー、言語サーバーといったサブプロセスにOTEL_*環境変数を渡さない設計です。サブプロセス側で独自にテレメトリを送りたい場合は、コマンド内で改めて変数を指定する必要があります。
メトリクスの粒度(カーディナリティ)を下げるにはどうすればよいですか
OTEL_METRICS_INCLUDE_SESSION_IDやOTEL_METRICS_INCLUDE_ACCOUNT_UUIDのようなカーディナリティ制御用の変数をfalseにします。属性数を減らし、バックエンドの保存コストを抑えられます。ただし分析の粒度も粗くなるため、どの分解軸を残すかは実際のダッシュボード用途に合わせて個別に判断する必要があります。