2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude CodeのOpenTelemetry対応を使い倒す——テレメトリ設計の背景から実践セットアップまで

2
Posted at

はじめに

Claude Codeを日常的に使っていると、ふと気になることがあります。「今月いくら使ったんだろう」「チームの誰がどれくらいトークンを消費しているんだろう」「キャッシュはちゃんと効いているのか」——しかし、ターミナルに流れていく会話ログを眺めているだけでは、これらの問いに答えることはできません。

Claude CodeはネイティブのOpenTelemetry(OTel)対応を備えています。サードパーティのラッパーやサイドカーは不要で、環境変数を数個設定するだけで、メトリクスとイベントログがOTLPプロトコルで送出されます。

本記事では、まずClaude Codeのテレメトリがなぜこのように設計されているのかを掘り下げた上で、ローカルでの動作確認からDocker Composeによる本格的な可視化基盤の構築までを段階的に解説します。

対象読者

  • Claude Codeの利用コストを定量的に把握したいエンジニア
  • チームへのClaude Code導入にあたり、利用状況の可視化基盤を構築したい管理者
  • OpenTelemetryの実践的な活用事例に興味がある方

前提知識

  • Claude Codeの基本的な使い方
  • Docker / Docker Composeの基礎
  • OpenTelemetryの概念(メトリクス、ログ、トレース)の概要レベルの理解

テレメトリ設計の背景——なぜメトリクスとイベントなのか

トレースが無い理由

OpenTelemetryには3つのシグナルタイプがあります——メトリクス、ログ(イベント)、トレースです。Claude Codeが出力するのはメトリクスとイベントの2種類のみで、トレース(スパン)は出力しません。

これはおそらく意図的な設計判断です。

トレースは、マイクロサービス間のリクエスト伝播を追跡するために設計されたシグナルです。Claude CodeはCLIツールであり、ユーザーのプロンプトがClaude Messages APIに送信され、レスポンスが返る——という本質的に2者間の同期的なやり取りです。分散トレースが真価を発揮する「複数サービスをまたぐリクエストチェーン」は存在しません。

代わりに、Claude Codeはイベントにprompt.id(UUID v4)を付与することで、1つのプロンプトから派生したすべてのイベントを相関付けできるようにしています。ユーザーがプロンプトを送信すると、そこから発生するツール実行、APIリクエスト、パーミッション判定のすべてが同じprompt.idを共有します。トレースの代替としては十分に機能する設計です。

メトリクスの粒度設計

Claude Codeのメトリクスは8種類と、多すぎず少なすぎない数に絞られています。

メトリクス名 何を測るか 単位
claude_code.session.count セッション開始数 count
claude_code.token.usage トークン消費量 tokens
claude_code.cost.usage セッションコスト USD
claude_code.lines_of_code.count コード変更行数 count
claude_code.commit.count コミット作成数 count
claude_code.pull_request.count PR作成数 count
claude_code.code_edit_tool.decision 編集ツールの許可/拒否判定 count
claude_code.active_time.total アクティブ時間 seconds

注目すべきは、これらがビジネスに直結するメトリクスに集中している点です。「APIレイテンシ」や「メモリ使用量」といったインフラ寄りのメトリクスはありません。Claude Codeのテレメトリは、インフラの健全性監視ではなくコスト管理と生産性の可視化を目的として設計されています。

各メトリクスには属性(attribute)が付与され、多次元的な分析が可能です。

claude_code.token.usage
  ├── type: "input" | "output" | "cacheRead" | "cacheCreation"
  └── model: "claude-opus-4-6" | "claude-sonnet-4-6" | ...

claude_code.cost.usage
  └── model: "claude-opus-4-6" | ...

claude_code.code_edit_tool.decision
  ├── tool_name: "Edit" | "Write" | "NotebookEdit"
  ├── decision: "accept" | "reject"
  ├── source: "config" | "hook" | "user_permanent" | "user_temporary" | ...
  └── language: "TypeScript" | "Python" | ...

イベントの設計——ログパイプラインの再利用

Claude Codeのイベントは、OTelのLogs/Events APIを通じて送出されます。5種類のイベントは、1つのプロンプトのライフサイクルをカバーするように設計されています。

ユーザープロンプト送信
  │
  ├── claude_code.user_prompt     ← プロンプトの受信を記録
  │
  ├── claude_code.tool_decision   ← ツール使用の許可/拒否
  │
  ├── claude_code.tool_result     ← ツール実行の結果
  │     └── tool_name, success, duration_ms, error
  │
  ├── claude_code.api_request     ← Claude APIへのリクエスト
  │     └── model, cost_usd, duration_ms, input_tokens, output_tokens
  │
  └── claude_code.api_error       ← APIエラー(発生時のみ)
        └── error, status_code, attempt

これらすべてのイベントが同じprompt.idを共有するため、「このプロンプトでいくらかかったか」「どのツールが失敗したか」をイベント単位で追跡できます。

プライバシー・バイ・デザイン

テレメトリ設計で特筆すべきは、デフォルトでプロンプト内容もツール入力も送信されないという点です。

  • claude_code.user_promptイベントにはprompt_length(文字数)のみが含まれ、プロンプト本文は含まれません
  • ツール実行結果にはツール名と成否のみが含まれ、bashコマンドの内容やファイルパスは含まれません
  • ファイルの中身やコードスニペットはいかなる場合も含まれません

これらの詳細情報を取得するには、明示的にオプトインが必要です。

環境変数 有効にすると デフォルト
OTEL_LOG_USER_PROMPTS プロンプトの本文がイベントに含まれる 無効
OTEL_LOG_TOOL_DETAILS bashコマンド、MCPサーバー名、ツール入力引数がイベントに含まれる 無効

コスト管理やチーム利用量の把握だけが目的であれば、これらを有効にする必要はありません。「誰がいくら使ったか」は分かるが「何をしていたか」は分からない——という線引きが、テレメトリのデフォルト設計に組み込まれています。

最速セットアップ——consoleエクスポーターで動作確認

まずは何も構築せずに、Claude Codeのテレメトリが動作することを確認しましょう。

# 3つの環境変数だけでテレメトリが動く
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_METRICS_EXPORTER=console
export OTEL_METRIC_EXPORT_INTERVAL=10000  # 10秒間隔(デフォルトは60秒)

claude

Claude Codeを起動して適当なプロンプトを送ると、10秒後にターミナルにメトリクスがJSON形式で出力されます。

{
  "resourceMetrics": [{
    "scopeMetrics": [{
      "metrics": [{
        "name": "claude_code.token.usage",
        "sum": {
          "dataPoints": [{
            "attributes": {
              "type": "input",
              "model": "claude-opus-4-6"
            },
            "asInt": "2847"
          }]
        }
      }]
    }]
  }]
}

イベント(ログ)も同様に確認できます。

export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_LOGS_EXPORTER=console

claude

動作が確認できたら、次のステップでOTLPエクスポーターに切り替えます。

本格セットアップ——OTel Collector + Prometheus + Grafana

Anthropicが公開しているclaude-code-monitoring-guideをベースに、Docker Composeで可視化基盤を構築します。

アーキテクチャ

Claude Code (CLI)
    │
    │ OTLP/gRPC (:4317)
    ▼
OTel Collector
    │
    │ Prometheus scrape (:8889)
    ▼
Prometheus (:9090)
    │
    │ データソース
    ▼
Grafana (:3000)

OTel Collectorの設定

otel-collector-config.yamlを作成します。

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    timeout: 1s
    send_batch_size: 1024
  memory_limiter:
    check_interval: 5s
    limit_mib: 512

exporters:
  prometheus:
    endpoint: "0.0.0.0:8889"
    metric_expiration: 180m
    enable_open_metrics: true
  debug:
    verbosity: detailed

service:
  pipelines:
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [prometheus, debug]
    logs:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [debug]

ポイントは以下の通りです。

  • metric_expiration: 180m: Claude Codeのセッションは断続的なので、メトリクスの有効期限を長めに設定します。短すぎるとセッション間でメトリクスが消失します
  • debugエクスポーター: 構築中はCollectorのログにテレメトリの中身が出力されるので、トラブルシューティングに有用です。本番運用時は除外してください
  • logsパイプライン: 現時点ではdebugエクスポーターのみですが、Lokiなどのログバックエンドを追加すればイベントも永続化できます

Prometheusの設定

prometheus.ymlを作成します。

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: "otel-collector"
    static_configs:
      - targets: ["otel-collector:8889"]

Docker Compose

docker-compose.ymlを作成します。

services:
  otel-collector:
    image: otel/opentelemetry-collector-contrib:latest
    command: ["--config=/etc/otel-collector-config.yaml"]
    volumes:
      - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
    ports:
      - "4317:4317"
      - "4318:4318"
      - "8889:8889"
    depends_on:
      - prometheus

  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    ports:
      - "9090:9090"
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.retention.time=200h"
      - "--web.enable-lifecycle"

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana_data:/var/lib/grafana
    depends_on:
      - prometheus

volumes:
  prometheus_data:
  grafana_data:

起動と接続

# 1. 可視化基盤を起動
docker compose up -d

# 2. Claude Codeのテレメトリを有効化
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:4317

# 3. Claude Codeを起動して操作する
claude

起動後のアクセス先は以下の通りです。

サービス URL 用途
Grafana http://localhost:3000 ダッシュボード(admin/admin)
Prometheus http://localhost:9090 メトリクス直接クエリ

Grafanaにログイン後、データソースとしてPrometheus(URL: http://prometheus:9090)を追加してください。

Grafanaダッシュボードで何を見るか

コスト分析

# 総コスト
sum(claude_code_cost_usage_USD_total)

# モデル別コスト
sum(claude_code_cost_usage_USD_total) by (model)

# ユーザー別コスト(チーム利用時)
sum(claude_code_cost_usage_USD_total) by (user_email)

トークン消費

# トークン種別ごとの消費量
sum(claude_code_token_usage_tokens_total) by (type)

# キャッシュ効率の確認
sum(claude_code_token_usage_tokens_total{type="cacheRead"})
  /
sum(claude_code_token_usage_tokens_total{type="cacheCreation"})

キャッシュ効率比(cacheRead / cacheCreation)は、Claude Codeの利用効率を測る重要な指標です。公式モニタリングガイドの実測データでは39:1という比率が報告されており、プロンプトキャッシュが効果的に機能していることが分かります。この比率が極端に低い場合、セッションを頻繁に切り替えすぎている可能性があります。

生産性指標

# トークン消費速度(5分間移動平均)
rate(claude_code_token_usage_tokens_total[5m])

# コード変更行数
sum(claude_code_lines_of_code_count_total) by (type)

# コミット・PR作成数
sum(claude_code_commit_count_total)
sum(claude_code_pull_request_count_total)

Prometheusでのメトリクス名は、OTelの定義(ドット区切り: claude_code.cost.usage)からアンダースコア区切り(claude_code_cost_usage_USD_total)に自動変換されます。単位やカウンターの_totalサフィックスも自動付与されます。

環境変数の全体像

Claude CodeのOTel対応で使用できる環境変数を整理します。

必須

変数 説明
CLAUDE_CODE_ENABLE_TELEMETRY 1 テレメトリのマスタースイッチ

エクスポーター設定

変数 値の例 説明
OTEL_METRICS_EXPORTER otlp, prometheus, console, none メトリクスのエクスポーター(カンマ区切りで複数指定可)
OTEL_LOGS_EXPORTER otlp, console, none イベント/ログのエクスポーター
OTEL_EXPORTER_OTLP_PROTOCOL grpc, http/json, http/protobuf OTLPプロトコル
OTEL_EXPORTER_OTLP_ENDPOINT http://localhost:4317 OTLPエンドポイント
OTEL_EXPORTER_OTLP_HEADERS Authorization=Bearer token 認証ヘッダー

エクスポート間隔

変数 デフォルト 説明
OTEL_METRIC_EXPORT_INTERVAL 60000(60秒) メトリクスの送出間隔(ミリ秒)
OTEL_LOGS_EXPORT_INTERVAL 5000(5秒) イベントの送出間隔(ミリ秒)

プライバシー制御

変数 デフォルト 有効にすると
OTEL_LOG_USER_PROMPTS 無効 プロンプト本文がイベントに含まれる
OTEL_LOG_TOOL_DETAILS 無効 bashコマンド、MCPサーバー名、ツール入力がイベントに含まれる

カーディナリティ制御

変数 デフォルト 説明
OTEL_METRICS_INCLUDE_SESSION_ID true セッションIDをメトリクス属性に含める
OTEL_METRICS_INCLUDE_VERSION false Claude Codeバージョンをメトリクス属性に含める
OTEL_METRICS_INCLUDE_ACCOUNT_UUID true アカウントUUIDをメトリクス属性に含める

大規模チームではOTEL_METRICS_INCLUDE_SESSION_ID=falseに設定することで、メトリクスのカーディナリティ(組み合わせ数)を大幅に削減できます。セッション単位の分析が不要な集計用途では、これを無効にすることでPrometheusのストレージ効率が向上します。

高度な設定

変数 デフォルト 説明
OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE delta メトリクスの時間集約方式。cumulativeに変更するとバックエンドによっては互換性が向上
OTEL_RESOURCE_ATTRIBUTES なし カスタムリソース属性(例: department=engineering,team.id=platform

OTEL_RESOURCE_ATTRIBUTESはチーム別・部署別のセグメント分析に有用ですが、値にスペースを含めることはできません。アンダースコアで代替してください。

# ❌ 動作しない
export OTEL_RESOURCE_ATTRIBUTES="org.name=My Organization"

# ✅ 正しい
export OTEL_RESOURCE_ATTRIBUTES="org.name=My_Organization"

settings.jsonでの永続化

毎回環境変数を設定するのは面倒なので、Claude Codeのsettings.jsonに記述して永続化できます。

{
  "env": {
    "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
    "OTEL_METRICS_EXPORTER": "otlp",
    "OTEL_LOGS_EXPORTER": "otlp",
    "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
    "OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4317"
  }
}

この設定ファイルの配置場所は以下の通りです。

スコープ パス 用途
ユーザー ~/.claude/settings.json 個人の開発環境
プロジェクト .claude/settings.json リポジトリ単位の設定
管理者(Managed) MDM配布 チーム全体にポリシーを強制

管理者がsettings.jsonをManaged設定として配布すれば、ユーザーが個別にテレメトリ設定を上書きすることを防止できます。

チーム導入時の考慮事項

認証の設定

OTLPエンドポイントに認証が必要な場合は、静的ヘッダーまたは動的ヘッダーを使用します。

# 静的ヘッダー
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer your-token"

# mTLS(メトリクス用)
export OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY=/path/to/client.key
export OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE=/path/to/client.crt

トークンの定期更新が必要な環境では、settings.jsonotelHeadersHelperにスクリプトを指定することで、動的にヘッダーを生成できます。デフォルトでは29分間隔でスクリプトが再実行されます。

メトリクスとイベントの送出先を分ける

メトリクスはPrometheusに、イベントログはLokiに——といった構成も、エンドポイントの個別指定で実現できます。

export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://prometheus-gateway:4318/v1/metrics
export OTEL_EXPORTER_OTLP_METRICS_PROTOCOL=http/protobuf

export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://loki-gateway:4318/v1/logs
export OTEL_EXPORTER_OTLP_LOGS_PROTOCOL=http/protobuf

標準属性によるセグメント分析

すべてのメトリクスとイベントには、以下の標準属性が自動付与されます。

属性 説明
session.id セッション識別子
user.account_uuid アカウントUUID
user.email ユーザーメール(OAuth認証時)
organization.id 組織UUID
terminal.type ターミナル種別(iTerm.app, vscode, cursor, tmux等)

terminal.typeは地味ですが興味深い属性です。VS Code拡張として使っているのか、ターミナルから直接使っているのか、tmux越しなのか——チームのClaude Code利用パターンを把握する手がかりになります。

Grafana Cloudへの直接送信(Collector不要)

ローカルにOTel Collectorを立てたくない場合、Grafana Cloudに直接送信する構成も可能です。

export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp-gateway-prod-ap-northeast-0.grafana.net/otlp
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic <base64-encoded-credentials>"

この構成ではCollectorのメンテナンスが不要になる反面、すべてのテレメトリが直接外部に送信されるため、OTEL_LOG_USER_PROMPTSOTEL_LOG_TOOL_DETAILSの有効化は慎重に判断してください。

既知の制限と注意点

CLIのみの対応

2026年3月時点で、OTelテレメトリが利用できるのはCLI版のClaude Codeのみです。Web版(claude.ai/code)では利用できません。この点はGitHubのIssue #32364でフィーチャーリクエストとして挙がっています。

テレメトリはオプトイン

CLAUDE_CODE_ENABLE_TELEMETRY=1を明示的に設定しない限り、テレメトリは一切送出されません。これはAnthropicのプライバシー方針として意図的な設計です。

deltaテンポラリティ

メトリクスのデフォルトのテンポラリティはdeltaです。一部のバックエンド(例: 古いバージョンのMimir)ではcumulativeが必要な場合があります。メトリクスが正しく表示されない場合は、OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=cumulativeを試してください。

まとめ

Claude CodeのOpenTelemetry対応は、「とりあえずメトリクスを出せるようにした」という最小限の実装ではありません。

  • トレースを省き、メトリクス+イベントに絞る判断は、CLIツールという性質に対して合理的
  • prompt.idによるイベント相関は、トレースなしでもプロンプト単位の追跡を可能にする
  • プロンプト内容をデフォルトで送信しない設計は、テレメトリとプライバシーの両立を示す
  • 8つのメトリクスはビジネスメトリクスに集中しており、コスト管理とROI測定に直結する

LLMベースの開発ツールに対して「いくらかかっているのか分からない」「チームの利用状況が見えない」という不安を持つのは自然なことです。Claude Codeは、その不安に対して標準的なプロトコル(OpenTelemetry)で回答を用意しています。環境変数を3つ設定するところから始めてみてください。

参考

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?