رفتن به محتوا

مشاهده‌پذیری با OpenTelemetry

وقتی ایجنت‌ها را در محیط production اجرا می‌کنی، به دید نسبت به کاری که انجام داده‌اند نیاز داری:

  • چه ابزارهایی را فراخوانی کرده‌اند
  • هر درخواستِ مدل چقدر طول کشیده است
  • چند توکن مصرف شده است
  • خطاها کجا رخ داده‌اند

Agent SDK می‌تواند این داده‌ها را به‌صورت traceها، metricها و log eventهای OpenTelemetry به هر backendی که OpenTelemetry Protocol (OTLP) را می‌پذیرد صادر کند — مثل Honeycomb، Datadog، Grafana، Langfuse، یا یک collectorِ self-hosted.

این راهنما توضیح می‌دهد که SDK چطور تله‌متری را منتشر می‌کند، چطور export را پیکربندی کنی، و چطور داده‌ها را پس از رسیدن به backend برچسب‌گذاری و فیلتر کنی. اگر می‌خواهی به‌جای export به یک backend، مصرفِ توکن و هزینه را مستقیماً از استریمِ پاسخِ SDK بخوانی، ردیابی هزینه و مصرف را ببین.

تله‌متری چطور از SDK جریان می‌یابد

Section titled “تله‌متری چطور از SDK جریان می‌یابد”

Agent SDK، Claude Code CLI را به‌عنوان یک child process اجرا می‌کند و از طریق یک pipeِ محلی با آن ارتباط می‌گیرد. این CLI به‌صورت توکار ابزارگذاریِ OpenTelemetry دارد: دورِ هر درخواستِ مدل و هر اجرای ابزار spanها را ثبت می‌کند، برای شمارنده‌های توکن و هزینه metric منتشر می‌کند، و برای پرامپت‌ها و نتایجِ ابزارها log eventهای ساختاریافته منتشر می‌کند. خودِ SDK تله‌متریِ مستقلی تولید نمی‌کند. در عوض، پیکربندی را به پروسه‌ی CLI پاس می‌دهد و CLI مستقیماً به collectorِ تو export می‌کند.

پیکربندی به‌صورت متغیرهای محیطی پاس داده می‌شود. به‌صورت پیش‌فرض، child process محیطِ اپلیکیشنِ تو را به ارث می‌برد، پس می‌توانی تله‌متری را در یکی از این دو جا پیکربندی کنی:

  • محیطِ پروسه (Process environment): متغیرها را پیش از شروعِ اپلیکیشن در shell، کانتینر یا orchestratorِ خود تنظیم کن. هر فراخوانیِ query() آن‌ها را خودکار برمی‌دارد، بدون تغییر کد. این رویکردِ توصیه‌شده برای استقرارهای production است.
  • گزینه‌های هر فراخوانی (Per-call options): متغیرها را در ClaudeAgentOptions.env (پایتون) یا options.env (تایپ‌اسکریپت) تنظیم کن. وقتی ایجنت‌های مختلف در یک پروسه نیاز به تنظیماتِ تله‌متریِ متفاوت دارند از این استفاده کن. در پایتون، env روی محیطِ به‌ارث‌رسیده merge می‌شود. در تایپ‌اسکریپت، env کلِ محیطِ به‌ارث‌رسیده را جایگزین می‌کند، پس ...process.env را در آبجکتی که پاس می‌دهی بگنجان.

این CLI سه سیگنالِ مستقلِ OpenTelemetry را export می‌کند. هرکدام کلیدِ فعال‌سازیِ خود و exporterِ خود را دارد، پس می‌توانی فقط آن‌هایی را که لازم داری روشن کنی.

سیگنالچه چیزی در خود داردفعال‌سازی با
Metricsشمارنده‌ها برای توکن‌ها، هزینه، نشست‌ها، خطوطِ کد، و تصمیم‌های ابزارOTEL_METRICS_EXPORTER
Log eventsرکوردهای ساختاریافته برای هر پرامپت، درخواستِ API، خطای API، و نتیجه‌ی ابزارOTEL_LOGS_EXPORTER
Tracesspanها برای هر تعامل، درخواستِ مدل، فراخوانیِ ابزار، و hook (بتا)OTEL_TRACES_EXPORTER به‌علاوه‌ی CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1

برای فهرستِ کاملِ نام‌های metric، نام‌های event و attributeها، به مرجعِ Monitoringِ Claude Code مراجعه کن. Agent SDK همان داده‌ها را منتشر می‌کند چون همان CLI را اجرا می‌کند. نام‌های span در خواندنِ traceهای ایجنت در ادامه فهرست شده‌اند.

فعال‌سازی export تله‌متری

Section titled “فعال‌سازی export تله‌متری”

تله‌متری خاموش است تا وقتی که CLAUDE_CODE_ENABLE_TELEMETRY=1 را تنظیم کنی و دستِ‌کم یک exporter انتخاب کنی. رایج‌ترین پیکربندی، هر سه سیگنال را از طریقِ OTLP HTTP به یک collector می‌فرستد.

مثالِ زیر متغیرها را در یک dictionary تنظیم می‌کند و آن‌ها را از طریقِ options.env پاس می‌دهد. ایجنت یک تسکِ واحد را اجرا می‌کند، و CLI همزمان با مصرفِ استریمِ پاسخ توسطِ حلقه، spanها، metricها و eventها را به collector در collector.example.com export می‌کند:

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
OTEL_ENV = {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
# Required for traces, which are in beta. Metrics and log events do not need this.
"CLAUDE_CODE_ENHANCED_TELEMETRY_BETA": "1",
# Choose an exporter per signal. Use otlp for the SDK; see the Note below.
"OTEL_TRACES_EXPORTER": "otlp",
"OTEL_METRICS_EXPORTER": "otlp",
"OTEL_LOGS_EXPORTER": "otlp",
# Standard OTLP transport configuration.
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://collector.example.com:4318",
"OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer your-token",
}
async def main():
options = ClaudeAgentOptions(env=OTEL_ENV)
async for message in query(
prompt="List the files in this directory", options=options
):
print(message)
asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
const otelEnv = {
CLAUDE_CODE_ENABLE_TELEMETRY: "1",
// Required for traces, which are in beta. Metrics and log events do not need this.
CLAUDE_CODE_ENHANCED_TELEMETRY_BETA: "1",
// Choose an exporter per signal. Use otlp for the SDK; see the Note below.
OTEL_TRACES_EXPORTER: "otlp",
OTEL_METRICS_EXPORTER: "otlp",
OTEL_LOGS_EXPORTER: "otlp",
// Standard OTLP transport configuration.
OTEL_EXPORTER_OTLP_PROTOCOL: "http/protobuf",
OTEL_EXPORTER_OTLP_ENDPOINT: "http://collector.example.com:4318",
OTEL_EXPORTER_OTLP_HEADERS: "Authorization=Bearer your-token",
};
for await (const message of query({
prompt: "List the files in this directory",
// env replaces the inherited environment in TypeScript, so spread
// process.env first to keep PATH, ANTHROPIC_API_KEY, and other variables.
options: { env: { ...process.env, ...otelEnv } },
})) {
console.log(message);
}

چون child process به‌صورت پیش‌فرض محیطِ اپلیکیشنِ تو را به ارث می‌برد، می‌توانی همین نتیجه را با export این متغیرها در یک Dockerfile، یک Kubernetes manifest یا یک shell profile و حذفِ کاملِ options.env به دست بیاوری.

Flush تله‌متری از فراخوانی‌های کوتاه‌عمر

Section titled “Flush تله‌متری از فراخوانی‌های کوتاه‌عمر”

این CLI تله‌متری را batch می‌کند و در بازه‌های زمانی export می‌کند. هنگامِ یک خروجِ تمیزِ پروسه، تلاش می‌کند داده‌های در انتظار را flush کند، اما این flush محدود به یک timeoutِ کوتاه است، پس اگر collector کند پاسخ بدهد ممکن است باز هم spanها از دست بروند. اگر پروسه‌ات پیش از خاموش‌شدنِ CLI کشته شود، هر چیزی که هنوز در batch buffer مانده از دست می‌رود. کوتاه‌کردنِ بازه‌های export هر دو پنجره را کاهش می‌دهد.

به‌صورت پیش‌فرض، metricها هر ۶۰ ثانیه و traceها و logها هر ۵ ثانیه export می‌شوند. مثالِ زیر هر سه بازه را کوتاه می‌کند تا داده‌ها همزمان با اجرایِ یک تسکِ کوتاه به collector برسند:

OTEL_ENV = {
# ... exporter configuration from the previous example ...
"OTEL_METRIC_EXPORT_INTERVAL": "1000",
"OTEL_LOGS_EXPORT_INTERVAL": "1000",
"OTEL_TRACES_EXPORT_INTERVAL": "1000",
}
const otelEnv = {
// ... exporter configuration from the previous example ...
OTEL_METRIC_EXPORT_INTERVAL: "1000",
OTEL_LOGS_EXPORT_INTERVAL: "1000",
OTEL_TRACES_EXPORT_INTERVAL: "1000",
};

traceها مفصل‌ترین نمای یک اجرای ایجنت را به تو می‌دهند. با تنظیمِ CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1، هر گامِ حلقه‌ی ایجنت به یک span تبدیل می‌شود که می‌توانی در tracing backendِ خود بازرسی‌اش کنی:

  • claude_code.interaction: یک نوبتِ واحد از حلقه‌ی ایجنت را در بر می‌گیرد، از دریافتِ یک پرامپت تا تولیدِ یک پاسخ.
  • claude_code.llm_request: هر فراخوانی به Claude API را در بر می‌گیرد، با نام مدل، latency و شمارشِ توکن به‌عنوان attributeها.
  • claude_code.tool: هر فراخوانیِ ابزار را در بر می‌گیرد، با child spanهایی برای انتظارِ مجوز (claude_code.tool.blocked_on_user) و خودِ اجرا (claude_code.tool.execution).
  • claude_code.hook: هر اجرایِ hook را در بر می‌گیرد. علاوه بر متغیرهای بالا، به detailed beta tracing نیاز دارد (ENABLE_BETA_TRACING_DETAILED=1 و BETA_TRACING_ENDPOINT).

spanهای llm_request، tool و hook فرزندانِ spanِ دربرگیرنده‌ی claude_code.interaction هستند. وقتی ایجنت از طریقِ ابزارِ Task یک ساب‌ایجنت می‌سازد، spanهای llm_request و toolِ ساب‌ایجنت زیرِ spanِ claude_code.toolِ ایجنتِ والد لانه می‌کنند، پس کلِ زنجیره‌ی واگذاری به‌صورت یک trace ظاهر می‌شود.

spanها به‌صورت پیش‌فرض یک attributeِ session.id حمل می‌کنند. وقتی چند فراخوانیِ query() را روی یک نشست انجام می‌دهی، در backendِ خود روی session.id فیلتر کن تا آن‌ها را به‌صورت یک خط‌زمانِ واحد ببینی. اگر OTEL_METRICS_INCLUDE_SESSION_ID روی یک مقدارِ falsy تنظیم شده باشد، این attribute حذف می‌شود.

پیوندِ traceها به اپلیکیشنِ تو

Section titled “پیوندِ traceها به اپلیکیشنِ تو”

این SDK به‌صورت خودکار W3C trace context را به subprocessِ CLI propagate می‌کند. وقتی query() را در حالی فراخوانی می‌کنی که یک spanِ OpenTelemetry در اپلیکیشنت فعال است، SDK مقادیرِ TRACEPARENT و TRACESTATE را به محیطِ child process تزریق می‌کند، و CLI آن‌ها را می‌خواند تا spanِ claude_code.interactionاش فرزندِ spanِ تو شود. آنگاه اجرای ایجنت به‌جای یک ریشه‌ی منفصل، درونِ traceِ اپلیکیشنِ تو ظاهر می‌شود.

وقتی propagationِ trace-context فعال است، CLI همچنین TRACEPARENT را به هر فرمانِ Bash و PowerShell که اجرا می‌کند فوروارد می‌کند. اگر فرمانی که از طریقِ ابزارِ Bash اجرا شده، spanهای OpenTelemetریِ خودش را منتشر کند، آن spanها زیرِ spanِ claude_code.tool.execution که فرمان را در بر می‌گیرد لانه می‌کنند.

وقتی TRACEPARENT را به‌صراحت در options.env تنظیم کنی، تزریقِ خودکار صرف‌نظر می‌شود، پس در صورتِ نیاز می‌توانی یک کانتکستِ والدِ مشخص را پین کنی. نشست‌های تعاملیِ CLI به‌کلی TRACEPARENTِ ورودی را نادیده می‌گیرند؛ فقط اجراهای Agent SDK و claude -p به آن احترام می‌گذارند. برای مرجعِ کاملِ span و attribute، Traces (beta) را در مرجعِ Monitoring ببین.

برچسب‌گذاریِ تله‌متری از ایجنتِ تو

Section titled “برچسب‌گذاریِ تله‌متری از ایجنتِ تو”

به‌صورت پیش‌فرض، CLI مقدارِ service.name را claude-code گزارش می‌کند. اگر چند ایجنت اجرا می‌کنی، یا SDK را در کنارِ سرویس‌های دیگری که به همان collector export می‌کنند اجرا می‌کنی، نام سرویس را override کن و resource attributeها را اضافه کن تا بتوانی در backend بر اساسِ ایجنت فیلتر کنی.

مثالِ زیر سرویس را تغییرِ نام می‌دهد و فراداده‌ی استقرار را الصاق می‌کند. این مقادیر به‌عنوانِ resource attributeهای OpenTelemetry روی هر span، metric و eventی که ایجنت منتشر می‌کند اعمال می‌شوند:

options = ClaudeAgentOptions(
env={
# ... exporter configuration ...
"OTEL_SERVICE_NAME": "support-triage-agent",
"OTEL_RESOURCE_ATTRIBUTES": "service.version=1.4.0,deployment.environment=production",
},
)
const options = {
env: {
...process.env,
// ... exporter configuration ...
OTEL_SERVICE_NAME: "support-triage-agent",
OTEL_RESOURCE_ATTRIBUTES:
"service.version=1.4.0,deployment.environment=production",
},
};

نسبت‌دادنِ اقدام‌ها به کاربرانِ نهاییِ تو

Section titled “نسبت‌دادنِ اقدام‌ها به کاربرانِ نهاییِ تو”

این CLI بر اساسِ credentialی که برای فراخوانیِ Anthropic استفاده می‌کند، attributeهای هویتی را به هر event الصاق می‌کند. وقتی اپلیکیشنی می‌سازی که از یک استقرارِ واحد به کاربرانِ نهاییِ بسیاری سرویس می‌دهد، این attributeها credentialِ سرویسِ تو را شناسایی می‌کنند، نه کاربرِ نهایی‌ای که ایجنت از طرفِ او اقدام کرده است.

برای اینکه فراخوانی‌های ابزار و فعالیتِ MCP قابل‌نسبت‌دادن به کاربرانِ نهاییِ اپلیکیشنت شوند، هویتِ کاربرِ نهایی را به‌عنوانِ resource attribute در هر فراخوانیِ query() تزریق کن. مقادیر را پیش از درج percent-encode کن، چون OTEL_RESOURCE_ATTRIBUTES کاما، فاصله و علامتِ مساوی را رزرو می‌کند. مثالِ زیر کاربرِ درخواست‌دهنده و tenant را به هر span و eventِ یک درخواست الصاق می‌کند:

from urllib.parse import quote
options = ClaudeAgentOptions(
env={
# ... exporter configuration ...
"OTEL_RESOURCE_ATTRIBUTES": f"enduser.id={quote(request.user_id)},tenant.id={quote(request.tenant_id)}",
},
)
const options = {
env: {
...process.env,
// ... exporter configuration ...
OTEL_RESOURCE_ATTRIBUTES: `enduser.id=${encodeURIComponent(request.userId)},tenant.id=${encodeURIComponent(request.tenantId)}`,
},
};

با الصاقِ هویتِ کاربرِ نهایی، eventهای tool_decision، tool_result، mcp_server_connection و permission_mode_changed به یک ردِ ممیزیِ هر-کاربری تبدیل می‌شوند که می‌توانی آن را به یک پلتفرمِ Security Information and Event Management (SIEM) فوروارد کنی. برای فهرستِ کاملِ eventهای مرتبط با امنیت و attributeهایی که هرکدام حمل می‌کنند، Audit security events را در مرجعِ Monitoring ببین.

کنترلِ داده‌ی حساس در exportها

Section titled “کنترلِ داده‌ی حساس در exportها”

تله‌متری به‌صورت پیش‌فرض ساختاری است. مدت‌زمان‌ها، نام‌های مدل و نام‌های ابزار روی هر span ثبت می‌شوند؛ شمارشِ توکن وقتی ثبت می‌شود که درخواستِ API زیربنایی داده‌ی usage برگرداند، پس spanهای درخواست‌های ناموفق یا لغوشده ممکن است آن‌ها را نداشته باشند. محتوایی که ایجنت می‌خواند و می‌نویسد به‌صورت پیش‌فرض ثبت نمی‌شود. این متغیرهای opt-in محتوا را به داده‌ی export‌شده اضافه می‌کنند:

متغیرچه اضافه می‌کند
OTEL_LOG_USER_PROMPTS=1متنِ پرامپت روی eventهای claude_code.user_prompt و روی spanِ claude_code.interaction
OTEL_LOG_TOOL_DETAILS=1آرگومان‌های ورودیِ ابزار (مسیرهای فایل، فرمان‌های shell، الگوهای جست‌وجو) روی eventهای claude_code.tool_result
OTEL_LOG_TOOL_CONTENT=1بدنه‌ی کاملِ ورودی و خروجیِ ابزار به‌عنوانِ span eventها روی claude_code.tool، با برشِ ۶۰ کیلوبایت. نیازمندِ فعال‌بودنِ tracing است
OTEL_LOG_RAW_API_BODIESJSONِ کاملِ درخواست و پاسخِ Anthropic Messages API به‌عنوانِ log eventهای claude_code.api_request_body و claude_code.api_response_body. برای بدنه‌های inline با برشِ ۶۰ کیلوبایت روی 1 تنظیم کن، یا file:<dir> برای بدنه‌های بدونِ‌برش روی دیسک با یک مسیرِ body_ref در event. بدنه‌ها کلِ تاریخچه‌ی گفتگو را در بر دارند و محتوای extended-thinking در آن‌ها redact شده است. فعال‌کردنِ این، به‌معنای رضایت به هر چیزی است که سه متغیرِ بالا فاش می‌کنند

این‌ها را غیرفعال نگه دار مگر اینکه pipelineِ observabilityِ تو برای ذخیره‌ی داده‌ای که ایجنت با آن سر و کار دارد تأیید شده باشد. برای فهرستِ کاملِ attributeها و رفتارِ redaction، Security and privacy را در مرجعِ Monitoring ببین.

این راهنماها موضوعاتِ مجاورِ مانیتورینگ و استقرارِ ایجنت‌ها را پوشش می‌دهند:

  • ردیابی هزینه و مصرف: داده‌ی توکن و هزینه را بدونِ یک backendِ بیرونی از استریمِ پیام بخوان.
  • میزبانیِ Agent SDK: ایجنت‌ها را در کانتینرهایی مستقر کن که می‌توانی متغیرهای OpenTelemetry را در سطحِ محیط تنظیم کنی.
  • Monitoring: مرجعِ کامل برای هر متغیرِ محیطی، metric و eventی که CLI منتشر می‌کند.