Claude apps gatewayのテレメトリ設定 — クライアントとゲートウェイをOTLPで追跡する
信号ごとに宛先を分ける設定、クライアントへ自動配信される環境変数、社内コレクターへの直送、配信失敗時の挙動、AWSでの収集経路を扱います。
Claude apps gatewayで何が二重に追跡できるか
Claude apps gatewayを経由すると、開発者側の設定を足さなくても、Claude CodeのOTLP(OpenTelemetry Protocol)エクスポートがゲートウェイへ届きます。そこから、設定した宛先へ中継されます。
ゲートウェイ自身も、認証・支出上限・upstreamエラーといった運用イベントを別系統のログとして出します。出所も内容も別物なので、片方だけ集めても運用の全体像は見えません。ゲートウェイ自身の監査ログ形式や運用ログレベルはデプロイと運用にあります。
この記事は、テレメトリを実際に流すまでの設定と、流れなかったときの原因の切り分けを扱います。前提は、gateway.yamlのlisten.public_urlが設定済みであることです。
信号ごとに宛先を分ける
telemetry.forward_toは宛先のリストです。各宛先はmetrics・logs・tracesを個別にopt-inし、既定はmetricsのみです。
telemetry:
forward_to:
- url: https://otel-collector.internal.example.com
headers:
Authorization: ${OTLP_TOKEN}
metrics: true
logs: false
traces: false
- url: https://api.datadoghq.com/api/v2/otlp
headers:
DD-API-KEY: ${DD_API_KEY}metricsはトークン数・リクエスト数・レイテンシーの集計値です。logsとtracesは違います。Claude Codeが開発者のマシンで実行したbashコマンド・ツールへの入力・ファイルパスまで運びうるため、アクセス制御と保持ポリシーがそのデータに見合う宛先だけで有効にします。
宛先は用途で分けられます。上のYAMLのように、コスト可視化のSaaSにはmetricsだけを渡し、logs/tracesは社内コレクターに絞る構成です。
trace span自体は、プロンプトの本文・ツール入力の詳細・ツール出力を既定で伏せています。中身まで含めるにはOTEL_LOG_USER_PROMPTS=1・OTEL_LOG_TOOL_DETAILS=1・OTEL_LOG_TOOL_CONTENT=1が別に要ります。forward_to側のtraces有効化とは別の防御線です。
URLの制約とプロキシ
URLはhttps://が必須です。例外はゲートウェイ自身のループバック上のコレクターで、書き方によって挙動が分かれます。
| 書き方 | 挙動 |
|---|---|
http://localhost:<port> | 挙動設定の検証は通る。CLAUDE_GATEWAY_ALLOW_LOOPBACK=1が無いとSSRFガードが全エクスポートをECONNREFUSED_SSRFで止める |
http://127.0.0.1:<port> / http://[::1]:<port> | 挙動同じ変数が無いとゲートウェイのboot自体が失敗する |
クラスター内のコレクターは、独立したHTTPSエンドポイントとして公開するか、この変数を設定したサイドカーとして動かします。
HTTPS_PROXYを設定している環境では、エクスポートもそのプロキシを通ります。社内コレクターへプロキシ無しで届かせたいときは、NO_PROXYにホスト名か、先頭にドットを付けたドメイン(.internal.example.com)を書きます。ドメイン指定にはゲートウェイ側がClaude Code v2.1.277以降であることが要ります。先頭にドットの無いエントリは、その名前だけに一致し、配下の名前には一致しません。CIDR範囲も一致しません。
proxy-only egressを有効にしている場合は注意が要ります。NO_PROXYに何か書かれているだけでproxy-only egressは無効になるため、コレクターはプロキシ側で許可します。
クライアントに届く設定と、届かない設定
telemetry.forward_toとlisten.public_urlを両方設定すると、ゲートウェイは接続済みの全クライアントへ/managed/settings経由で環境変数をプッシュします。CLIのテレメトリは既定でオフなので、これが有効化の引き金になります。
CLAUDE_CODE_ENABLE_TELEMETRY=1OTEL_METRICS_EXPORTER・OTEL_LOGS_EXPORTER・OTEL_TRACES_EXPORTER:forward_toのどれかがその信号を有効にしていればotlp、無ければnoneOTEL_EXPORTER_OTLP_ENDPOINT=<public_url>OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
固定ラベルを付ける設定(後述)を入れると、OTEL_RESOURCE_ATTRIBUTESも加わります。エンドポイントはpublic_urlから組み立てられるので、metricsとlogsは開発者側にもポリシー側にもOTELの設定が要りません。
プッシュされた変数はmanagedティアで適用され、開発者がローカルで設定した同名の変数に勝ちます。/loginでサインインしたCLIは、OTLP/HTTPエクスポートが有効なら、ローカルに書かれたエンドポイントも無視してゲートウェイへ送ります。開発者が別のOTLPエンドポイントを自分のマシンに書いていても、そちらへは流れません。
宛先の無い信号は、ゲートウェイが受け取ったうえで破棄します。すでに自前のコレクターでClaude Codeのテレメトリを集めているなら、そのコレクターをforward_toに加えます。logsやtracesも出しているなら、その信号も有効にしておきます。
tracesは、有効化に要るフラグだけが自動配信の対象外です。
tracesまで流すための手順
- 1
ゲートウェイ側でtracesを有効にする
forward_toの宛先のうち、tracesを受けたいものにtraces: trueを書きます。これでOTEL_TRACES_EXPORTERがotlpとしてプッシュされます。 - 2
ポリシーのenvにフラグを置く
tracesは
CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1が各クライアントに要ります。ゲートウェイはこれをプッシュしないので、managed policyのenvブロックで配ります。 - 3
対象のグループだけに絞る
1を置くのは、トレースしたいグループのポリシーだけにします。このフラグを書かないポリシーは、match: {}の全体ポリシーに書かれた値を引き継ぎます。特定のグループのクライアントに、開発者がローカルで有効にしても送らせたくないときは、そのグループのポリシーで0を置きます。 - 4
開発者の承認を通す
プッシュされたエンドポイントは、対話セッションで承認ダイアログを出します。フラグも同じダイアログで承認されます。
hookスパンや内容付き属性まで含むトレースが要る場合は、この上に別の構成を重ねます。手順はBETA_TRACING_ENDPOINTでdetailed beta tracingの送信先を切り替えるにあります。
承認ダイアログは、配られる変数の種類で出方が違います。モデル選択や数値上限のような設定は、ダイアログ無しで適用されます。プロキシ・ベースURL・空でないOTEL_EXPORTER_OTLP_ENDPOINTは必ず承認を求めます。承認の対象を確認したいときは、ダイアログに変数名が表示されます。
開発者が承認を拒否すると、Claude Codeはポリシーを適用せずそのセッションを終了します。claude -pやAgent SDKのような非対話の実行はダイアログを出せないため、その実行に限ってポリシーを適用し、承認としては記録しません。
中継をやめて社内コレクターへ直送する
ゲートウェイの中継を通さず、セッションから直接コレクターへ送らせることもできます。managed policyのenvブロックでOTEL_EXPORTER_OTLP_ENDPOINTにコレクターのhttps://ベースURLを書く方法です。Claude Codeが/v1/metrics・/v1/logs・/v1/tracesを後ろに足して送ります。
中継と直送の違い
ゲートウェイ経由の中継
forward_toの宛先へ、ゲートウェイがそのまま転送します。複数宛先への振り分けや信号ごとのopt-inはここで行います。配信失敗はゲートウェイのログに残ります。
コレクターへの直送
OTEL_EXPORTER_OTLP_HEADERSで認証し、開発者のゲートウェイのセッショントークンは送られません。各開発者のClaude Codeがv2.1.265以降である必要があります。
直送には、Claude Code側の事前検査があります。どれか1つでも満たさない信号は、直送せずに中継のまま残ります。
- エンドポイントはゲートウェイ自身が配ったものである(MDMプロファイルやローカルの
managed-settings.jsonに書いた同名の値は対象外) - URLが
https://、またはhttp://のループバックアドレスである - URLが
/v1/<信号名>で終わり、クエリとフラグメントを持たない(信号別のOTEL_EXPORTER_OTLP_METRICS_ENDPOINTのような変数では、パスまで自分で書く) - ゲートウェイ自身のホスト宛てではない
otelHeadersHelperが、どの設定ソースにも設定されていない
直送で変わるのは送り先だけです。どの信号を出すかは、これまでどおりOTEL_*_EXPORTERで決まります。エンドポイントだけでは出力は始まりません。ゲートウェイが変数をプッシュしている環境では、プッシュ済みの値を明示したエンドポイントが上書きします。forward_toのどの宛先も有効にしていない信号だけは、自分でOTEL_*_EXPORTER=otlpを置きます。プッシュが無い環境では、CLAUDE_CODE_ENABLE_TELEMETRY=1・各OTEL_*_EXPORTER・OTEL_EXPORTER_OTLP_PROTOCOL=http/protobufも自分で置きます。
開発者がサインアウトするか別のゲートウェイにサインインすると、直送は止まり、残ったバッチも送らず捨てられます。
ユーザー帰属とラベル
CLIは、/loginでサインインしたセッションで、認証済みのIdP(アイデンティティプロバイダー)の属性をエクスポートに付けます。user.idはIdPのsubject、user.emailはメールアドレス、user.groupsはグループ一覧のカンマ区切り文字列です。identity.source: gateway-oidcも付きます。
ゲートウェイを介さない構成では、OTEL_RESOURCE_ATTRIBUTESで部署などの属性を自分で足します。ゲートウェイの属性は最後に適用されるので、OTEL_RESOURCE_ATTRIBUTESにuser.*やidentity.*を書いても、そのセッションでは無視されます。イベントの中身や指標カタログの全量はClaude CodeのOpenTelemetry監視にあります。
Claude DesktopとCowork
Claude DesktopとCowork経由のセッションも、同じゲートウェイでサインインすればuser.email・user.groups・enduser.idが付きます。user.groupsには、各開発者のマシンにClaude Desktop 1.24012以降が必要です。端末・Desktop・Coworkを、user.emailまたはuser.groupsの1本のクエリで束ねられます。
enduser.subはIdPが発行するsubクレームで、メールアドレスが変わっても同じ値のままです。端末のセッションは同じ値をuser.idに入れます。端末のuser.idとDesktop・Coworkのenduser.subを突き合わせれば、1人の利用を3つの面にまたがって追えます。Desktop・Coworkでは、user.idは匿名の識別子で、subjectではありません。
次の場合は、ゲートウェイが属性を切り詰めず、丸ごと外します。端末側には影響しません。
- パーセントエンコードしたグループ一覧が255文字を超える、またはグループ名にカンマか等号が含まれる: Desktop・Coworkの
user.groups - subjectがパーセントエンコード後に255文字を超える、空白・印字可能なASCII以外の文字・
, ; = \ " %のいずれかを含む:enduser.sub
Desktopへテレメトリを渡すには、ポリシーにdesktopキーを置いて/user/bootstrapをオプトインする必要があります。Desktopのエクスポートは1つのエンコーディングで統一され、既定はhttp/protobufです。ポリシーのenvでOTEL_EXPORTER_OTLP_PROTOCOLなどをhttp/jsonにすれば、JSONになります。
固定ラベル
telemetry.resource_attributesは、service.namespaceやdeployment.environment.nameのような固定ラベルを、ゲートウェイ経由の全セッションに付けます。ラベルは全宛先に同じものが届き、forward_toとlisten.public_urlの両方を設定したときだけ付きます。ラベルはメトリクスの各データポイントにも写されます。バックエンドがリソース属性を索引しない場合でも、ラベルで絞り込めます。
ラベルの名前と値には制約があります。
- 名前は英数字と
.・_・-だけで、user.・enduser.・identity.で始まる名前やservice.nameのような予約名は使えない - 値は255文字以内の印字可能なASCIIで、空白と
, ; = \ " %は使えない - 数値や
true/falseに見える値は、引用符で囲んで文字列にする
ルールを破るラベルがあると、ゲートウェイは起動を拒否し、起動エラーにそのラベル名が出ます。
端末のセッションにはOTEL_RESOURCE_ATTRIBUTESとして配られます。ポリシーのenvに同じ変数を書くと、そのポリシーに一致する端末はラベルでなく、書いた値を受け取ります。
配信に失敗したとき
ゲートウェイはテレメトリをバッファも再試行も保存もしません。宛先に届かなかったエクスポートは、遅れて届けずに捨てます。宛先ごとに成否が独立していて、送ってきたクライアントにはどちらでも成功が返ります。
つまり、ダッシュボードにデータが出なくても、クライアント側にはエラーが出ません。失敗の手がかりはゲートウェイのログだけです。
- 5回連続で配信に失敗した宛先は、成功するまで30秒ずつ転送を止め、止めるたびにログに残す
- エラー応答・タイムアウト・接続エラーは、すべて失敗に数える
400・413・415・422・431は、コレクターがペイロードを不正または過大として拒否した応答で、失敗回数を進めも戻しもしない。この場合は転送を続け、その宛先の初回の拒否と100回ごとに、宛先名とステータスを含む警告を出す
AWSでクライアントテレメトリとコンテナメトリクスを別経路で集める
クライアントのmetrics/logs/tracesは、AWS Distro for OpenTelemetry(ADOT)コレクターのような内部サービスをhttps://で立てて受けます。telemetry.forward_toの宛先にそれを指定し、コレクターからAmazon CloudWatch・Amazon Managed Service for Prometheus・任意のOTLPバックエンドへ書き出します。
ゲートウェイ自身の監査ログ・運用ログは別経路です。ECS Fargateではawslogsドライバーが追加設定なしにstderrを/ecs/claude-gatewayロググループへ配送します。EKSではPodのログが既定でCloudWatchへ届かず、監査証跡が失われます。コンテナログ収集を有効にしたAmazon CloudWatch Observability add-onか、Fluent Bit DaemonSetを別途入れます。どちらの場合も、ログはCloudWatch Logs Insightsで検索でき、アラームはメトリクスフィルタから作れます。
タスク単位のCPU・メモリ・ネットワークは、Container Insightsを有効にして取得します。EKSでは同じadd-onを入れます。
aws ecs update-cluster-settings \
--cluster claude-gateway \
--settings name=containerInsights,value=enabledforward_toの書き方はupstreamのクラウドを問わず共通です。一方、コレクター接続の具体例が用意されているのはAWS向けのデプロイガイドだけです。Google Cloud向けのガイドには、Telemetryの節がなく、設定リファレンスへのリンクがあるのみです。Google Cloudで運用する場合は、自前のOTelコレクターをhttps://で公開してforward_toに指定し、Cloud LoggingやCloud Monitoringへ書き出す構成を自分で設計します。
テレメトリは事後の可視化です。「誰が今どれだけ使っているか」を強制するのは、支出上限のenforcementが担う別の仕組みです。
ゲートウェイのバージョンで変わった挙動
テレメトリまわりの設定には、ゲートウェイ側のClaude Codeのバージョンに依存するものがあります。古いゲートウェイでキーが読めずに起動しない例もあります。
テレメトリ設定の必要バージョン
- v2.1.261Desktopへ返す符号化が既定のprotobufになる
これより前は、Desktopへ返す設定が
http/json固定でした。protobufしか受けないコレクターは、Desktopのエクスポートを拒否していました。 - v2.1.265信号別のセレクターと直送に対応する
OTEL_*_EXPORTERは、宛先が有効にした信号だけotlpになります。これより前は、宛先のない信号も含めて3つともotlpでした。Desktop・Coworkのuser.email・user.groupsもこの版からです。コレクターへの直送には、開発者の端末側もこの版が要ります。 - v2.1.274enduser.subが付く
IdPの
subクレームが、Desktop・Coworkのテレメトリに載ります。 - v2.1.277NO_PROXYにドメイン指定が使える
先頭にドットを付けたドメインを
NO_PROXYに書けます。 - v2.1.281resource_attributesが書ける
これより前のゲートウェイは、
telemetry.resource_attributesを見つけると起動しません。レプリカを全部上げてからキーを足し、ロールバックの前にキーを外します。
よくあるつまずき
| 症状 | 見る場所 |
|---|---|
| クライアントから何も届かない | 見る場所listen.public_urlとforward_toの両方があるか。片方だけではテレメトリは有効にならない |
| ループバックのコレクターに届かない | 見る場所CLAUDE_GATEWAY_ALLOW_LOOPBACK=1がゲートウェイの環境にあるか |
| tracesだけ出ない | 見る場所CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1をポリシーのenvで配っているか |
| ダッシュボードが空なのにクライアントにエラーが無い | 見る場所ゲートウェイのログに配信失敗や一時停止の記録があるか |
| Desktopのexportだけコレクターに拒否される | 見る場所コレクターがprotobuf専用なら、ゲートウェイがv2.1.261以降か |
| EKSで監査ログが見つからない | 見る場所CloudWatch Observability add-onかFluent Bitを入れたか。awslogsドライバーはECS Fargateの機能 |
まとめ
テレメトリは、クライアントのOTLPを中継するレイヤーと、ゲートウェイ自身のログの2本立てで、配線も別々に設計します。logsとtracesは機微な中身を運ぶので、宛先を絞ったうえで有効にし、直送が要る組織はポリシー側で送り先を指定します。