
Claude Code のテレメトリで会話本文・API・ツール入出力をローカルに出してみた
Claude Code は OpenTelemetry でメトリクスやイベントを出せます。公式ドキュメントにイベントやメトリクスの一覧はあるのですが、実際の出力サンプルは見当たりませんでした。どんな形で、どこまで出るのか手元で見たくなったので試してみました。
使うのは OpenTelemetry の console エクスポーターだけです。Collector も SIEM も立てず、Claude Code がモデルとやり取りしている中身(入力したプロンプトや API のリクエスト/レスポンス本文など)をローカルのターミナルに出します。
どこまで見えるか
console エクスポーターで出せるのは、メトリクスやイベント名だけではありません。環境変数を足していくと、出力の中身が段階的に増えます。
入力プロンプトの全文、Messages API のリクエスト本文(会話履歴・system prompt・tools 一式)、レスポンス本文(assistant の応答テキスト)、ツールの入出力まで、手元のターミナルへ出てきます。
Collector + Grafana で可視化する構成はよく見かけますが、ここではもっと手前の「ローカルで会話本文を目視する」ところを見ます。監査やログ保全の要件を検討するときに、どの粒度で何が残せるかを自分で確かめられます。
前提
テレメトリは既定で無効です。CLAUDE_CODE_ENABLE_TELEMETRY=1 が起点になります。
プロンプト本文・API 本文・ツール詳細は、既定ではマスク(<REDACTED>)されるか、そもそも出力されません。中身を出すには専用の環境変数で明示的に有効化します。挙動は検証日時点のものです。仕様は変わり得るので、公式ドキュメントも併せて確認してください。
出力サンプルは headless 実行(claude -p "...")から1ターンずつ採りました。対話セッションで claude を起動しても同じイベントが出ます(対話時の注意は後述します)。
実機で事前に押さえておくと良い点が2つあります。
出力は1行1JSONではなく、Node の inspect 形式(body: "claude_code.xxx" / attributes: { ... } というオブジェクト整形)で出ます。目視には十分ですが、jq で直接パースはできません。プログラムで処理したいなら、後述の OTLP(OpenTelemetry の標準送信プロトコル)で Collector に送る方法を使います。
すべてのイベントの attributes に識別子が乗ります(user.email / user.id / session.id / organization.id / user.account_uuid / user.account_id)。この記事では <USER_EMAIL> などのプレースホルダーに置き換えて表示しています。ログを貼って共有するときは要注意です。
console エクスポーターでプロンプト本文を出す
Claude Code がそのままターミナルにイベントを吐きます。claude を起動する前に、テレメトリ有効化・console エクスポーター・OTEL_LOG_USER_PROMPTS をまとめて設定します。
# テレメトリ有効化
export CLAUDE_CODE_ENABLE_TELEMETRY=1
# console エクスポーターに切り替え(ログ/メトリクスをターミナルへ)
export OTEL_LOGS_EXPORTER=console
export OTEL_METRICS_EXPORTER=console
# プロンプト本文を出す(既定はマスク)
export OTEL_LOG_USER_PROMPTS=1
# すぐ流れてくるようにエクスポート間隔を短縮(デバッグ用)
export OTEL_METRIC_EXPORT_INTERVAL=5000
export OTEL_LOGS_EXPORT_INTERVAL=1000
# headless で1ターン実行(console 出力はその場で stdout に出る)
claude -p "pongと返答して"
この状態で claude -p を実行すると、claude_code.user_prompt や claude_code.api_request といったイベントが stdout に出ます。claude_code.user_prompt の prompt には、入力した文字列がそのまま入ります。
body: "claude_code.user_prompt",
attributes: {
"user.email": "<USER_EMAIL>",
"organization.id": "<ORGANIZATION_ID>",
"session.id": "<SESSION_ID>",
"event.name": "user_prompt",
"prompt.id": "<PROMPT_ID>",
prompt_length: "9",
prompt: "pongと返答して",
},
OTEL_LOG_USER_PROMPTS を設定しない既定だと、同じイベントでも prompt は <REDACTED> になります(prompt_length は出ます)。
prompt_length: "9",
prompt: "<REDACTED>",
中身が取れないのではなく、既定でマスクされているだけ、という違いです。
API リクエスト/レスポンス本文を出す(OTEL_LOG_RAW_API_BODIES)
OTEL_LOG_RAW_API_BODIES を立てると、Messages API のリクエストとレスポンスの本文がまるごとイベントに乗ります。
# インライン(イベントの body に直接埋め込む。60KB を超えると途中で切り詰められる)
export OTEL_LOG_RAW_API_BODIES=1
claude_code.api_request_body と claude_code.api_response_body というイベントが出ます。公式ドキュメントの表現では、リクエスト本文は会話履歴(entire conversation history)を含みます。body に system prompt / messages / tools などリクエストパラメータ一式が入り、body_length は切り詰め前の本来の長さです。
"event.name": "api_request_body",
body: "{\"model\":\"claude-opus-4-8\",\"messages\":[{\"role\":\"user\",\"content\":[{\"type\":\"text\",\"text\":\"...会話本文...\"}]}],\"tools\":[...]}",
body_length: "96553",
body_truncated: "true",
model: "claude-opus-4-8",
レスポンス側には、assistant の応答本文がそのまま入ります。今回は「pongと返答して」という指示なので、content に {"type":"text","text":"pong"}、stop_reason や usage も乗っています。
"event.name": "api_response_body",
body: "{\"model\":\"claude-opus-4-8\",\"id\":\"<MESSAGE_ID>\",\"role\":\"assistant\",\"content\":[{\"type\":\"text\",\"text\":\"pong\"}],\"stop_reason\":\"end_turn\",\"usage\":{...}}",
body_length: "786",
request_id: "<REQUEST_ID>",
インライン(=1)では body が 60KB を超えると途中で切り詰められ、body_truncated: "true" が付きます。上のリクエストは body_length が 96553 ですが、body に実際に入るのは 60KB までです。全文が要るなら次の file:<dir> を使います。
会話履歴は本文ごと残りますが、extended thinking(思考ブロック)は対象外です。公式ドキュメントには、リクエスト本文・レスポンス本文のいずれでも extended-thinking content は redacted と記載があります(今回の単発検証では thinking が発生せず、この挙動自体は実演していません)。
本文を丸ごと(切り詰めなし)ファイルに残す(file:<dir>)
OTEL_LOG_RAW_API_BODIES にディレクトリを渡すと、本文をファイルに書き出します。
export OTEL_LOG_RAW_API_BODIES=file:/path/to/dir
このときイベントは body の代わりに body_ref(保存ファイルへの絶対パス)を持ちます。
body_ref: "<DIR>/<UUID>.request.json",
body_length: "104987",
保存されるファイルは、リクエストが UUID 名で切り詰めなしの全文、レスポンスが request_id 名です。
<UUID>.request.json 104987 bytes(切り詰めなしの全文。inline の body_length 96553 と対照)
<REQUEST_ID>.response.json 786 bytes
response.json の中身は通常の Messages API レスポンス JSON で、content に assistant の応答テキストが入ります。実際にどの粒度の会話履歴が残るのかを確認・共有したいときに向いています。
ツールの入出力まで見たい場合
ツールの入出力も出せます。ただし console / logs 構成では、有効化する環境変数を取り違えやすいので注意します。
OTEL_LOG_TOOL_CONTENT はトレース(CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1 + OTEL_TRACES_EXPORTER)が前提で、console / logs だけでは効きません。logs 経路でツール詳細を見たいなら OTEL_LOG_TOOL_DETAILS=1 です。claude_code.tool_result イベントに tool_input / tool_parameters が乗ります。
"event.name": "tool_result",
tool_name: "Bash",
success: "true",
tool_parameters: "{\"bash_command\":\"echo\",\"full_command\":\"echo hello-otel\",\"description\":\"Echo test string\"}",
tool_input: "{\"command\":\"echo hello-otel\",\"description\":\"Echo test string\"}",
OTEL_LOG_TOOL_DETAILS を設定しない既定だと、tool_input / tool_parameters は出ません。OTEL_LOG_TOOL_CONTENT と混同しないよう注意してください。
対話セッションでライブ確認する(ローカル Collector)
console エクスポーターは headless(-p)やパイプ向きです。対話で claude を起動すると TUI が端末を専有し、console 出力はセッションを抜けるまで表示されません(抜けた瞬間にまとめて出てきます)。
対話を続けながらライブで追うには、ログの出口を TUI と別プロセスに分けます。OTLP でローカルの Collector に送り、Collector 側のペインに debug エクスポーターで流すのが分かりやすいです。
Collector は以下の設定にしました。
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
exporters:
debug:
verbosity: detailed
service:
pipelines:
logs:
receivers: [otlp]
exporters: [debug]
metrics:
receivers: [otlp]
exporters: [debug]
ターミナル1で Collector を起動します。このペインにイベントが流れます。実機では otel/opentelemetry-collector 0.154.0 が GRPC:4317 / HTTP:4318 で起動し、Everything is ready まで確認できました。
docker run --rm -p 4317:4317 -p 4318:4318 \
-v "$(pwd)/otel-collector-config.yaml":/etc/otelcol/config.yaml:ro \
otel/opentelemetry-collector:latest
ターミナル2で対話セッションを開きます。OTLP 送信に切り替え、本文を出す環境変数を設定します。
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_LOGS_EXPORTER=otlp
export OTEL_METRICS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
export OTEL_LOG_USER_PROMPTS=1
export OTEL_LOG_RAW_API_BODIES=1
claude
TUI とログ表示がプロセスごと分かれるので、対話を止めずに user_prompt / api_request_body / tool_result などをリアルタイムに追えます。Grafana などにつなぐ手前の「収集できている」確認ができます。
おわりに
Claude Code の OpenTelemetry 出力を、console エクスポーターだけで手元に出してみました。Collector を立てなくても、プロンプト本文から Messages API のリクエスト/レスポンス本文、ツールの入出力まで順に見えました。file:<dir> を使えば切り詰めなしの全文も残せます。
これらの出力は既定では無効で、OTEL_LOG_TOOL_DETAILS と OTEL_LOG_TOOL_CONTENT のように経路で効き方が変わるものもあります。どの粒度で何が残るかは、手元で1つずつ出して確かめるのが早かったです。
監査やログ保全の要件を検討している方は、まず console エクスポーターで会話本文を目視して、残せる粒度を把握してから Collector 構成に移ると無理がないと思います。





