メインコンテンツまでスキップ

ファーストパーティの OpenTelemetry トレーシング: 2 つの経路、1 つのトレース

上級

2026 年の大半、Claude API 呼び出しをトレースするとは、スパンを自分で書くことでした。スパンを開き、messages.create を呼び、usage を属性にコピーし、スパンを閉じる。エージェントのオブザーバビリティはそれを上手にやるためのページであり、名前が何を意味するかについてのページであり続けています。

このページは、変わった部分についてです。API と SDK が、ベータとして、それらのスパンを自ら出力するようになり、しかも手書きしていたよりはるかに多くを出力します。1 回の API リクエストの内部にあるモデルリクエストごとのスパン、API があなたに代わって実行したサーバーツールごとのスパン、コンパクションごとのスパン、Managed Agents のターンごとのスパン。これらは Anthropic 側で起きることで、手動の計装には構造上見えません。

これを有効にする独立した経路が 2 つあり、最も高くつく誤解は、両者が重複することです。ドキュメントを一段落も読まずに両方を有効にすると、すべての Messages リクエストが同じスパン名で 2 回現れ、トークンのダッシュボードが二倍になります。

What you'll learn
  • SDK トレーシング、API トレーシング、あるいは両方の中から選び、それぞれが何を見られて何を見られないかを正確に知る
  • 各経路をセットアップする: コード内のトレーサープロバイダ、Console または Admin API 経由の送信先
  • 重複するスパンをまたいでトークンを正しく合算する: 二重計上を止める唯一のルール
  • コンテンツモードを意図的に選び、何があなたの選択を上書きするか(HIPAA/FERPA/K-12、ゼロデータ保持)を知る
  • traceparent で API のスパンをアプリケーションのトレースに結合し、それらを消してしまう sampled フラグを避ける
  • 配信ルールを乗り切る: at-least-once、ベストエフォート、そして 24 時間の失敗後の自動無効化

2 つの経路​

同じことをする 2 つの方法ではありません。実行の異なる半分を見ます。

得られるものSDK トレーシングAPI トレーシング
Messages API と Sessions API のリクエストはいはい
トークン使用量はいはい
1 回の API リクエスト内部の各モデルリクエスト—はい
Managed Agents のターン—はい
API が実行するサーバーツールと MCP コネクタツール—はい
ツールランナーが実行する自前のクライアントツールはい—
セルフホストのサンドボックス内のツールはい—
ファイルアップロードなど、その他のリクエストはい—
セットアップ方法コードConsole または Admin API
設定できる人任意の開発者admin
対象となるクライアントSDK を使うクライアントのみcurl を含む任意のクライアント

区分は一本の線に沿っています。SDK はあなたのプロセスがすることを見て、API は Anthropic 側がすることを見ます。 Web 検索のようなサーバーツールは API リクエストの内部で動きます。あなたのプロセスはそれを観測できないので、そのスパンを出すのは API トレーシングだけです。あなた自身の get_weather 関数はあなたのプロセスで動くので、そのスパンを出すのは SDK トレーシングだけです。

だからほとんどの本番構成では「両方」が本当の答えであり、下の重複ルールが例外的なケースではない理由です。

この形を注意深く読んでください。罠が含まれているからです。2 リクエストの会話に対して anthropic.messages.create は4 回現れます。SDK から 2 回(種別 CLIENT)、API から 2 回(種別 SERVER)で、各 API スパンはその SDK スパンを親に持ちます。再配信という意味での重複ではありません。同じリクエストを両端から行った、2 つの正当な観測です。

SDK トレーシングをセットアップする​

SDK のスパンには権限も Console へのアクセスも要りません。SDK はアプリケーションがすでに登録したトレーサープロバイダを使うので、配線すべき Anthropic 固有のエクスポーターはありません。

Guided walkthrough1 of 4
  1. スパンは現行の Python、TypeScript、C#、Go、Java、PHP、Ruby の SDK に含まれています。Java では最小バージョンが `anthropic-java` 2.73.0 です。バージョンを固定してください。ベータの注記によると、新しい SDK リリースでスパン、属性、オプション、環境変数の名前が変わることがあります。

最小限の SDK トレーシング — まずコンソールエクスポーターで (Python)

from anthropic import Anthropic
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor

# Register BEFORE the first traced call. Swap ConsoleSpanExporter for an
# OTLP exporter once you can see spans in the terminal.
provider = TracerProvider()
provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(provider)

# Record prompts and responses, and label this conversation.
client = Anthropic(open_telemetry={"traces": {"content_mode": "content"}})

tracer = trace.get_tracer("my-service")
with tracer.start_as_current_span("answer_question"):
  message = client.with_options(
      open_telemetry={**client.open_telemetry, "conversation_id": "conv_42"}
  ).messages.create(
      model="claude-opus-5-5",
      max_tokens=1024,
      messages=[{"role": "user", "content": "Hello, Claude"}],
  )

知っておく価値のある SDK オプション​

オプション(Python の綴り)環境変数デフォルト
traces.content_modeANTHROPIC_OPEN_TELEMETRY_TRACES_CONTENT_MODEmetadata_only
traces.max_content_bytesANTHROPIC_OPEN_TELEMETRY_TRACES_MAX_CONTENT_BYTES0.75 MB
conversation_id—なし
tracer_provider—登録済みのグローバルプロバイダ
propagationANTHROPIC_OPEN_TELEMETRY_PROPAGATIONオン
open_telemetry(オフスイッチ)ANTHROPIC_OPEN_TELEMETRYオン

初見だとそれぞれ 1 時間を失う挙動が 2 つあります。

  • クライアントに open_telemetry を渡すと、環境変数が丸ごと上書きされます。入れ子のキーも含めて。オブジェクトから省いたキーは、変数が設定されていても、黙って表のデフォルトに戻ります。ゼロから作るのではなく、既存のオブジェクトからオブジェクトを組み立ててください。
  • TypeScript で @opentelemetry/instrumentation-undici を使う場合(@opentelemetry/auto-instrumentations-node が取り込みます)は、propagation: false を設定してください。そのパッケージのバグが各リクエストに2 つ目の traceparent ヘッダーを追加し、トレースコンテキストが無効になって、結合が黙って壊れます。

API トレーシングをセットアップする​

API トレーシングにはコードの変更がまったく要りません。送信先、つまりオブザーバビリティ基盤の OTLP エンドポイントと認証情報を登録すると、API がそこへスパンをポストします。

始める前に必要なもの:

  • Console 組織の admin ロール。developer ロールは送信先を表示できますが、作成も変更もできません。
  • HTTPS の 443 番ポートで protobuf を受け付ける OTLP/HTTP エンドポイント。 セルフホストの人を直撃する要件です。標準的な OpenTelemetry Collector は OTLP/HTTP をポート 4318で待ち受けるので、手前にロードバランサ、リバースプロキシ、または再設定したレシーバが必要です。gRPC の選択肢はなく、443 以外のポートもありません。
  • そのエンドポイントの認証情報。リクエストヘッダーに入れます。保存後、Console は値を再表示しません。

Admin API で telemetry destination を作成する (curl)

curl --fail-with-body -sS "https://api.anthropic.com/v1/organizations/telemetry_destinations" \
-H "x-api-key: $ANTHROPIC_ADMIN_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: telemetry-destinations-2026-08-11" \
-H "content-type: application/json" \
-d '{
  "endpoint_url": "https://gateway.example.com/otlp",
  "headers": {"authorization": "Bearer YOUR_OBSERVABILITY_API_KEY"},
  "traces": {"content_mode": "metadata_only"},
  "workspaces": {"type": "all"}
}'

エンドポイント URL の形に注意してください。ベースの OTLP URL を渡し、/v1/traces は API に付けさせます。パスのプレフィックスは許されます。プラットフォームがまったく別の場所でトレースを受け取る場合は、任意のトレースエンドポイント URL を設定しますが、同じホストでなければなりません。

デフォルトに任せず、意図的に決めるべき設定が 3 つあります。

  • ワークスペース — all、selected、all except。all は後から作成されるワークスペースも含みます。通常は望むことで、ときにまさに望まないことです。送信先は、リクエストやセッションが実際に実行されたワークスペースのスパンだけを受け取ります。
  • コンテンツモード — 後述します。
  • 最大コンテンツサイズ — フルコンテンツモードでのみ適用されます。Console で掲載されているパートナーを選ぶと、そのプラットフォームが受け付ける値が事前入力されます。Custom では自己責任です。

その後、この順序で確認します。送信先のメニューからテストスパンを送り、anthropic.test スパンが届くことを確認する。選択したワークスペースで実際のリクエストを送る。Delivery 列が Healthy になっているか確認する。プラットフォームを service.name = claude-platform でフィルタする。各ステップで約 1 分見込んでください。送信先の変更も、ヘルス列も、それくらい遅れます。

コンテンツモードと、何があなたの選択を上書きするか​

すべての送信先とすべての SDK クライアントは、2 つのコンテンツモードのどちらかを持ちます。

  • メタデータのみ(metadata_only) — デフォルト。ID、タイミング、ステータス、トークン数、そして自分で選んだテキスト(エージェント名、ツール名と説明、MCP サーバー名)。
  • フルコンテンツ(content) — 上記すべてに加えて、モデルのプロンプトと応答。スパンのリファレンスでは、これらの属性に Content バッジが付いています: gen_ai.system_instructions、gen_ai.input.messages、gen_ai.output.messages、gen_ai.tool.call.arguments、anthropic.tool_result.content。

フルコンテンツは、チームが実際にやりたいこと、つまり失敗した会話を読むことや、実トラフィックから評価を構築することのためにトレースを使えるものにします。同時に、あなたのプロンプトとユーザーの入力を第二のシステムへ移し、あなた自身ではなくそのベンダーの保持とアクセス制御の下に置きます。エージェントがアップロードするものと同じ計算です。有効にすることは、あなたのオブザーバビリティ提供者に、アプリケーションデータが持つのとほぼ同じ権限を与えることになります。

2 つの上書きは記憶に値します。どちらも紛らわしいサポートチケットを生むからです。

  • Anthropic との HIPAA、FERPA、K-12 のデータ取り扱い制限があると、送信先はメタデータのみに強制されます。送信先の設定が何であれ。SDK のスパンは影響を受けません。あなた自身のプロセスはコンテンツを出力できます。症状は「フルコンテンツはオンで、Console もそう言っているのに、プロンプトは CLIENT スパンにしか現れない」です。
  • ゼロデータ保持はフルコンテンツと両立します。 Messages API のリクエストでは、API はエクスポートされるコンテンツを配信まで、メモリ上にのみ保持します。Managed Agents はそもそも ZDR の対象外で、OpenTelemetry を使っても保持は変わりません。

コンテンツの上限と切り詰め​

各スパンはデフォルトで最大 0.75 MB のコンテンツを保持します。これは英語テキストの 200k トークンのコンテキストウィンドウに収まり、かつオブザーバビリティ基盤やプロキシに共通の 1 MB のリクエスト上限を下回るように選ばれています。1M トークンのウィンドウ全体には約 4 MB が必要です。

コンテンツが上限を超えると、スパンは短縮され、anthropic.content.truncated が true に設定されます。削除の順序は規定されており、トレースから評価を構築する人には重要です。

  • リクエストスパンは、まずシステムプロンプトを、次に最も古いメッセージを削除します。
  • ツールスパンは、結果の末尾からブロックを削除します。
  • 画像とドキュメントは種類としてのみ現れ、バイト列は決して含まれません。

つまり「すべてのトレースを評価ケースとして再生する」という素朴なパイプラインは、anthropic.content.truncated でフィルタしない限り、システムプロンプトのない会話を黙って流し込んできます。そのフィルタを、後から発見するのではなく、パイプラインの最初の 1 行にしてください。

唯一のルール: 各トークンを一度だけ数える​

ここは二度読むべきセクションです。トークン使用量の属性は、リクエストごとに複数のスパンに現れます。意図的です。各スパンが自分のステップを報告するからです。受け取ったものをすべて合算すると過大計上になり、誤ったレベルを合算すると過小計上になります。

Guided walkthrough1 of 5
  1. Messages リクエストに SDK スパンと API スパンの両方がある場合は、API スパンを合算します。どちらも `anthropic.messages.create` という名前なので、名前ではフィルタできません。スパン種別で見分けてください。SDK スパンは CLIENT で、その子の API スパンは SERVER です。`service.name` = `claude-platform` でのフィルタも有効です。

もう一つ、カウントのルールではありませんが、誤った数字から守ってくれることがあります。gen_ai.usage.input_tokens は、キャッシュ読み取りとキャッシュ書き込みをすでに含んでいます。そこに gen_ai.usage.cache_read.input_tokens を足すと、最も安いトークンを二重に数えることになります。それらのトークンが互いにどれだけの費用かはプロンプトキャッシュを参照してください。

トレースは課金記録ではない

Anthropic は、エクスポートされたスパンが使用量の完全な記録であることを保証しないと明言しています。配信はベストエフォートなのでスパンが失われることがあり、さらに呼び出し側は traceparent の sampled フラグをオフにすることで、リクエストのスパンを丸ごと抑制できます。キーごとの会計、たとえば漏洩したキーの発見や請求書の突き合わせには、スパンを一つも生まなかったリクエストも数える Usage API を使ってください。トレースはデバッグとコストの帰属のためのもので、台帳ではありません。

API スパンを自分のトレースに結合する​

デフォルトでは、API スパンは独自のトレースに存在します。技術的には正しく、ほとんど役に立ちません。どの機能やユーザーが呼び出しを引き起こしたのか分からないからです。

API は各リクエストから W3C の traceparent ヘッダーを読みます。SDK では、自分のスパンの内側で SDK を呼び、W3C トレースコンテキストのプロパゲーターを登録していれば、これは無料で手に入ります。(アプリケーションが B3 などの別のプロパゲーターに標準化している場合は、W3C をそれと並べて追加してください。SDK はあなたのプロパゲーターでヘッダーを書きます。)他のクライアントでは、ポストする前に、アクティブなスパンのコンテキストを自分でヘッダーに注入します。

そして、誰もが驚くフラグがあります。

sampled フラグはヒントではなく、スパンのオン/オフスイッチ

受信した traceparent の sampled フラグがオフなら、API はそのリクエストのスパンも、その下のスパンも出力しません。つまりアプリケーションでのヘッドサンプリングが、Anthropic 側のテレメトリがそもそも存在するかどうかを決めます。1% サンプリングのサービスが API トレーシングを有効にすると、モデルリクエストとサーバーツールのスパンの 1% しか得られず、機能が壊れていると結論づけるでしょう。コレクターでテールサンプリングするか、トレースしたい経路では sampled フラグを強制的にオンにしてください。

伝播は、ほとんどの人が予想するより一歩先まで及びます。Messages API がMCP コネクタ経由であなたの MCP サーバーを呼ぶとき、params._meta に W3C の traceparent を渡すので、それを読むサーバーは自分のスパンを API のスパンの下に付けられます。tools/call リクエストではその親は anthropic.mcp_tool_use スパンで、他のメッセージでは anthropic.messages.create です。トレースされないリクエストは traceparent をまったく送りません。クライアント側は状況がまちまちです。Python の mcp パッケージはバージョン 2.0 から、C# の ModelContextProtocol パッケージは、トレースコンテキストを _meta で転送します。TypeScript、Go、Java、Ruby、PHP の MCP SDK は自力ではそれを行いません。

配信ルールと、送信先が死ぬ仕組み​

API 側のエクスポートは Anthropic のインフラからあなたのエンドポイントへのプッシュです。つまり独自の失敗のセマンティクスを持ち、プロセス内の OTLP エクスポーターよりもウェブフックに近いものです。

性質挙動
重複At least once。トレース ID + スパン ID で重複排除する。
損失ベストエフォート。失われたスパンは再送されない。
圧縮各配信の最初のリクエストは Content-Encoding: gzip で gzip 圧縮される。400 または 415 の場合、同じスパンが圧縮なしですぐに再送される。
リトライタイムアウト、接続/TLS/DNS の失敗、408、429、5xx の後に限定的なリトライ。その他の失敗はリトライされない。
タイムアウトTLS ハンドシェイクは 5 秒以内、レスポンスヘッダーは 5 秒以内、配信ごとに合計 10 秒(圧縮なしの再送を含む)。
User agentUser-Agent: Claude-Platform。許可リストのルールに便利。

そして、API が送信先を完全に無効化し、人が再度有効にするまでエクスポートを止める 3 つのケースがあります。

  1. エンドポイントが 3xx のリダイレクトを返す。リダイレクトは追跡されません。送信先を最終的な URL に向けてください。
  2. エンドポイントのホスト名が非パブリックな IP アドレスに解決される。VPC へのトンネルはありません。パブリックなコレクターを公開するか、マネージドなプラットフォームを使ってください。
  3. すべての配信が 24 時間失敗する。

3 つ目が運用上の危険です。誰にも気づかれずにローテーションされたオブザーバビリティの API キーは、Failing の送信先として 1 日を過ごし、その後 Disabled になります。再有効化は Console での手動クリック(ワークスペースフィルタを All にした状態)であり、自動復旧ではありません。このページから一つだけアラートを張るなら、Delivery の状態にしてください。

組織ごとの上限​

上限値
送信先(無効なものを含む)10
一つの送信先に選択できるワークスペース1,000
送信先ごとのリクエストヘッダー20
ヘッダー名の長さ128 バイト
ヘッダー値の長さ4,096 バイト
すべてのヘッダー名と値の合計16,384 バイト
エンドポイント URL の長さ2,048 文字

Managed Agents のセッションを読む​

セッションは「1 トレース」という前提を壊し、解決策はトレース ID ではなくグルーピングキーです。

セッションのスパンは複数のトレースに落ちることがあります。新しいルートトレースから送られた後続のリクエストは新しいトレースを開始します。またマルチエージェントのオーケストレーションでは、セッションに複数のスレッドがあります。したがって:

  • 一つのスレッドをトランスクリプトとして — gen_ai.conversation.id(セッションのスレッド ID)でグループ化し、開始時刻でソートします。
  • セッション全体、すべてのスレッド — トレースをまたいで anthropic.session.id でグループ化します。

スパンの形は、頭に入れておく価値があります。すでにダッシュボードがあるかもしれない汎用の GenAI 規約とは一致しないからです。anthropic.session.turn は gen_ai.operation.name = invoke_agent を持ち、一つのスレッドの running 状態にまたがります。リクエストが開始したターンはそのリクエストのスパンの子になり、別のスレッドが返信したために始まったターンには親がまったくありません。フルコンテンツモードでは、ターンスパンがスレッドのコンテンツを保持します。gen_ai.system_instructions はスレッドの最初のターンにのみ、gen_ai.input.messages、gen_ai.output.messages です。アドバイザースレッドは意図的により薄く、gen_ai.agent.name は anthropic.advisor で、指示と入力の属性はありません。

4 つのケースでは、API のツールスパンがまったく出ません。そしてそれぞれが、トレーシングが壊れていると誰かに思わせてきました。アプリケーションが実行するツール(そのスパンは SDK のツールランナーが出します)、セルフホストのサンドボックス内のツール(SDK の環境ワーカーが出し、anthropic.environment.work の下にまとまります)、マルチエージェントまたはアドバイザーのツール、そして auto の権限ポリシーまたは user.tool_confirmation イベントによって拒否されたツール使用です。拒否された呼び出しはツールスパンを残しません。エージェントが試みたことを監査するなら、トレースではなくセッションイベントを読んでください。

よくある間違い​

  • 受け取ったすべての anthropic.messages.create スパンを合算する。 リクエストごとに正当な観測が 2 つ、同じ名前。まずスパン種別か service.name でフィルタしてください。もっともらしく、誤っていて、ちょうど二倍になったコスト値を生む間違いです。
  • 普段のサンプリングレートでスパンが来ると期待する。 sampled がオフの traceparent は API のスパンを完全に抑制します。あなたのサービスでのヘッドサンプリングは、Anthropic のテレメトリのヘッドサンプリングです。
  • 素の Collector を送信先に向ける。 4318 の OTLP/HTTP は 443 の HTTPS エンドポイントではありません。手前にプロキシを置かないと、送信先は決して配信しません。
  • フルコンテンツをロギングのフラグとして扱う。 プロンプトとユーザー入力をオブザーバビリティのベンダーに移します。データ取り扱いの責任者と決めてください。HIPAA/FERPA/K-12 の制限は、API スパンについてだけ黙ってそれを上書きします。
  • anthropic.content.truncated を確認せずにトレースから評価を構築する。 切り詰めはまずシステムプロンプトを落とします。評価コーパスから、ちょうど挙動を決めた部分が抜け落ちます。
  • Failing の送信先を放置する。 24 時間の失敗で無効化され、再有効化は手動です。スパン量ではなく Delivery の状態でアラートを張ってください。スパン量はゼロになる直前まで問題なさそうに見えます。
  • これらの属性名を 40 枚のパネルにハードコードする。 スパンは、タグ付きリリースのないリポジトリの特定のコミット(e57c543b、2026 年 9 月 24 日)の GenAI 規約に従っており、ベータの注記は名前を変更する権利を留保しています。エージェントのオブザーバビリティのマッピング層の習慣は、ここでは一段と強く当てはまります。

スパンの行き先​

OTLP を受け付けるプラットフォームならどれでも動きます。Anthropic は Arize AI、Braintrust、Databricks、Datadog、Grafana Cloud、Honeycomb、Langfuse、LangSmith、New Relic、PostHog、Sentry、Splunk との連携ガイドを文書化しています。Console で掲載されているプロバイダを選ぶと、生のエンドポイントとヘッダーを求める代わりに、そのプラットフォーム自身の認証情報を求め、受け付けるコンテンツサイズを事前入力します。

Claude Code、Agent SDK、Cowork については、これは別のシステムで別のスイッチ(CLAUDE_CODE_ENABLE_TELEMETRY など)があり、エージェントのオブザーバビリティで扱っています。ここで送信先を有効にしてもそれらには何も影響せず、逆も同様です。

Check yourself

0/3
  1. SDK トレーシングと API トレーシングの両方を有効にし、すべての anthropic.messages.create スパンの gen_ai.usage.input_tokens を合算しました。何が起きますか。
  2. サービスはトレースの 1% をヘッドサンプリングしており、telemetry destination を追加したばかりです。なぜモデルリクエストのスパンがほとんど届かないのですか。
  3. オブザーバビリティの API キーがローテーションされたため、送信先が 1 日 Failing になっています。この後どうなりますか。
Enter キーまたはスペースキーでカードを裏返します。左右の矢印キーでカードを移動できます。用語を表示しました。
1 / 14
Key takeaways
  • 2 つの経路、実行の 2 つの半分: SDK はあなたのプロセスを、API は Anthropic 側を見る。ほとんどの本番構成は両方を望む。
  • どちらの経路も同じリクエストについて anthropic.messages.create を出力する。何かを合算する前に、スパン種別で一つのソースを選ぶ。
  • API スパン内では一つのレベル(messages.create か model_request、両方は決して)を合算し、コンパクションはちょうど一か所から加える。
  • スパンはデバッグと帰属のためのもので、課金のためではない。配信はベストエフォートで、sampled がオフの traceparent はリクエストを丸ごと消す。台帳には Usage API を使う。
  • sampled フラグはヒントではなくオン/オフスイッチ。1% サンプリングのサービスは、Anthropic 側のスパンの 1% しか得られない。
  • フルコンテンツはプロンプトをオブザーバビリティのベンダーに移す。HIPAA/FERPA/K-12 の制限は API スパンについてだけそれを上書きする。知らなければ非常に紛らわしい症状になる。
  • トレースから評価を構築する前に anthropic.content.truncated を確認する。切り詰めはまずシステムプロンプトを落とす。
  • 送信先の Delivery 状態でアラートを張る。24 時間の失敗で無効化され、復旧は手動クリック。

次へ​

  • エージェントのオブザーバビリティ — gen_ai.* の名前の意味、それらがどれも安定していない理由、そしてこのページが扱わない Claude Code のテレメトリスイッチ
  • キャッシュ診断 — スパンに予期しないキャッシュ読み取りが見えたとき、その理由を説明するリクエストごとのフィールド
  • Managed agents — このページがグループ化の方法を教える、スパンの元となるセッション、ターン、スレッド

出典と参考資料​