Skip to content

原文(日本語に翻訳)

claude_code.tool OTELスパンに agent_id および parent_agent_id 属性を追加し、バックグラウンドサブエージェントのスパンが dispatch した Agent ツールスパンの配下に正しくネストされるようトレースの親子関係を修正

原文(英語)

Added agent_id and parent_agent_id attributes to claude_code.tool OTEL spans, and fixed trace parenting so background subagent spans nest under the dispatching Agent tool span

概要

Claude Code v2.1.145では、OpenTelemetry(OTEL)のトレーシングが強化されました。claude_code.tool スパンに新たに agent_idparent_agent_id 属性が追加され、複数エージェントが協調動作する際のトレース情報をより詳細に把握できるようになりました。また、バックグラウンドで動作するサブエージェントのスパンが、それを起動した Agent ツールスパンの子として正しく関連付けられるバグが修正されたことで、分散トレーシングの可視化が正確になりました。

基本的な使い方

OTEL連携を有効にした状態でClaude Codeを実行すると、ツールスパンに自動的に agent_idparent_agent_id が付与されます。

bash
# OTEL エンドポイントを設定してClaude Codeを起動
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
export OTEL_SERVICE_NAME="claude-code"

claude "複数エージェントを使ってタスクを処理して"

生成されるスパン属性の例:

json
{
  "name": "claude_code.tool",
  "attributes": {
    "tool.name": "Bash",
    "agent_id": "agent-abc123",
    "parent_agent_id": "agent-root456",
    "session.id": "session-xyz789"
  }
}

実践例

Jaegerでのトレース可視化

JaegerをバックエンドにOTELトレースを収集して、エージェント間の呼び出し関係を可視化します。

bash
# Jaegerをローカルで起動
docker run -d --name jaeger \
  -p 16686:16686 \
  -p 4317:4317 \
  jaegertracing/all-in-one:latest

# Claude Codeの環境変数を設定
export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
export OTEL_SERVICE_NAME="claude-code"
export OTEL_EXPORTER_OTLP_PROTOCOL="grpc"

# エージェントを使うタスクを実行
claude "並行してファイルを分析して結果をまとめて"

# ブラウザで http://localhost:16686 を開いてトレースを確認

agent_idを使ったフィルタリングと分析

特定のエージェントのみのスパンを抽出して分析します。

python
# otel_analysis.py - OTELスパンをフィルタリング

import json

def analyze_agent_spans(spans_file):
    """エージェントIDでスパンをグループ化して分析"""
    with open(spans_file) as f:
        spans = json.load(f)
    
    # agent_idでグループ化
    by_agent = {}
    for span in spans:
        attrs = span.get('attributes', {})
        agent_id = attrs.get('agent_id')
        parent_id = attrs.get('parent_agent_id')
        
        if agent_id:
            if agent_id not in by_agent:
                by_agent[agent_id] = {
                    'spans': [],
                    'parent': parent_id
                }
            by_agent[agent_id]['spans'].append(span)
    
    # 親子関係を表示
    for agent_id, data in by_agent.items():
        parent = data['parent'] or 'root'
        span_count = len(data['spans'])
        print(f"Agent {agent_id} (parent: {parent}): {span_count} spans")

analyze_agent_spans('otel_spans.json')

Grafana Tempoでの長期モニタリング

Grafana Tempoと連携してエージェントのパフォーマンスをダッシュボードで監視します。

yaml
# otel-collector-config.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317

processors:
  # agent_idでスパンをフィルタリング
  filter:
    spans:
      include:
        match_type: strict
        attributes:
          - key: agent_id
            value: ".*"

exporters:
  tempo:
    endpoint: "http://tempo:4317"

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [filter]
      exporters: [tempo]

注意点

  • この機能はOTELトレーシングを有効化している場合のみ動作します(OTEL_EXPORTER_OTLP_ENDPOINT 環境変数が必要)
  • parent_agent_id はルートエージェントの場合は null または未設定になります
  • バックグラウンドサブエージェントのスパンが正しくネストされるよう親子関係の修正が含まれています(以前のバージョンではフラットに表示されていた問題が解消)
  • OTEL連携はClaude Code Enterprise機能の一部として提供される場合があります
  • スパン属性の追加によって、トレースデータのストレージ使用量がわずかに増加する可能性があります

関連情報