---
title: مراقبة Claude Agent SDK باستخدام OpenTelemetry (2026)
description: 'قم بتجهيز حلقة Claude Agent SDK باستخدام OpenTelemetry في TypeScript: قم بتفعيل تصدير التتبع (trace export)، وقراءة شجرة spans الخاصة بـ claude_code، وإرسال الـ spans الحقيقية إلى backend.'
url: https://nerdleveltech.com/ar/claude-agent-sdk-opentelemetry-typescript-tutorial
language: ar
date: '2026-07-15'
category: ai-ml
tags:
  - claude agent sdk
  - opentelemetry
  - observability
  - ai agents
  - typescript
  - tracing
  - agent evaluation
  - langfuse
markdown_url: https://nerdleveltech.com/ar/claude-agent-sdk-opentelemetry-typescript-tutorial.md
attribution: 'Source: NerdLevelTech — https://nerdleveltech.com/ar/claude-agent-sdk-opentelemetry-typescript-tutorial'
terms: https://nerdleveltech.com/llms.txt
---

# مراقبة Claude Agent SDK باستخدام OpenTelemetry (2026)

يمكن لـ Claude Agent SDK تصدير كل طلب نموذج، واستدعاء أداة، وتنفيذ خطاف (hook) في تشغيل العميل على شكل تتبعات OpenTelemetry — ولكن التتبع يكون متوقفاً بشكل افتراضي ومقيداً بعلامة بيتا (beta flag)، كما أن شجرة النطاقات (span tree) التي ينتجها لها نظام تسمية خاص يتداخل جزئياً فقط مع الاصطلاحات الدلالية لـ OpenTelemetry GenAI[^1][^2]. يقوم هذا الدرس التعليمي بتفعيل التتبع في TypeScript، وقراءة التسلسل الهرمي الحقيقي للنطاقات، وربطه بنظام خلفي (backend) يمكنك معاينته فعلياً.

## ملخص

قم بضبط `CLAUDE_CODE_ENABLE_TELEMETRY=1` و `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1`، ووجه `OTEL_TRACES_EXPORTER=otlp` نحو نقطة نهاية للمجمع (collector endpoint)، وعندها تصبح كل دورة للعميل عبارة عن نطاق جذر `claude_code.interaction` مع نطاقات فرعية لكل طلب نموذج (`claude_code.llm_request`)، وكل استدعاء أداة (`claude_code.tool`، مع نطاقات فرعية لـ `.blocked_on_user` و `.execution`)، وكل خطاف (`claude_code.hook`، المقيد ببيتا بشكل منفصل)[^1][^2]. هناك خمس سمات في تلك النطاقات — `gen_ai.system`، و `gen_ai.request.model`، و `gen_ai.response.id`، و `gen_ai.response.finish_reasons`، و `gen_ai.tool.call.id` — موثقة صراحةً كسمات اصطلاحية دلالية لـ OpenTelemetry GenAI؛ أما كل شيء آخر، بما في ذلك أسماء النطاقات نفسها، فيتبع مساحة الأسماء الخاصة بـ Anthropic وهي `claude_code.*`[^2]. بيئة التشغيل: Node 18+ (تم البناء وفحص الأنواع مقابل Node 22.22.3). SDK: `@anthropic-ai/claude-agent-sdk@0.3.210`[^3]. وقت البناء: 25-30 دقيقة.

## ما ستتعلمه

- أي متغيرات البيئة تقوم بتفعيل التتبعات والمقاييس وأحداث السجلات بشكل مستقل، ولماذا تحتاج التتبعات إلى علامة واحدة لا تحتاجها الإشارتان الأخريان[^1]
- التسلسل الهرمي الدقيق للنطاقات التي يصدرها Agent SDK، وصولاً إلى مستوى السمات، وأي السمات تظهر فقط عندما تختار التقاط المحتوى[^2]
- كيفية بناء عميل بسيط لاستدعاء الأدوات يستحق التتبع، وتوجيه بيانات التتبع الخاصة به إلى مستقبل محلي يمكنك قراءته فعلياً
- كيفية جعل نطاق `claude_code.interaction` الخاص بـ Claude Agent SDK يظهر كنطاق فرعي لتتبع تطبيقك الخاص، بدلاً من أن يكون جذراً منفصلاً
- ما إذا كان تتبع Claude Agent SDK يتبع بالفعل الاصطلاحات الدلالية لـ OpenTelemetry GenAI، وماذا يعني هذا التمييز بالنسبة للوحات البيانات (dashboards) الخاصة بك
- كيفية الحصول على التكلفة وزمن الاستجابة لكل طلب بطريقتين مختلفتين — إحداهما لا تحتاج إلى OpenTelemetry على الإطلاق — ومتى تستخدم كل منهما

## المتطلبات الأساسية

- Node.js 18.0.0 أو أحدث — لا يزال ملف `package.json` الخاص بـ SDK يحدد `"engines": {"node": ">=18.0.0"}` في الإصدار الحالي؛ تم بناء هذا الدرس وفحص أنواعه مقابل Node 22.22.3[^3]
- `@anthropic-ai/claude-agent-sdk@0.3.210` (الإصدار `latest` المؤكد في السجل وقت كتابة هذا النص، والمنشور في 2026-07-14)، بالإضافة إلى التبعيات المجاورة `zod@^4.0.0`، و `@anthropic-ai/sdk@>=0.93.0`، و `@modelcontextprotocol/sdk@^1.29.0`[^3]
- TypeScript 5.x أو أحدث مع تفعيل وضع `strict` (تم فحص أنواع كود هذا الدرس باستخدام TypeScript 7.0.2، وهي علامة `latest` على npm وقت كتابة هذا النص)
- مفتاح `ANTHROPIC_API_KEY` إذا كنت ترغب في تشغيل حلقة العميل من البداية إلى النهاية ورؤية النطاقات الحقيقية تصل إلى المجمع — الكود أدناه تم فحص أنواعه مقابل SDK الحقيقي، ولكن خط أنابيب الكتابة الآلي هذا لا يملك مفتاح API مدفوع، لذا لم يتم تنفيذ استدعاءات نماذج حية؛ راجع قسم "التحقق" لمعرفة ما تم تشغيله وما لم يتم تشغيله بالضبط

## لماذا لا يحل `total_cost_usd` هذه المشكلة بالفعل؟

يتضمن تدفق استجابة Agent SDK بالفعل رسالة `result` تحتوي على `total_cost_usd`، و `duration_ms`، واستهلاك الرموز (tokens) لكل استدعاء `query()` بالكامل[^4]. هذا يكفي لتسجيل "هذا التشغيل كلف 0.03 دولار". لكنه لا يكفي للإجابة على "أي استدعاء أداة واحد في هذا التشغيل كان مسؤولاً عن معظم زمن الاستجابة"، أو "هل اضطر النموذج لإعادة المحاولة قبل أن ينجح استدعاء أداة معين"، أو "هل أداة خادم MCP معين هي الجزء البطيء باستمرار في كل تشغيل". هذه الأسئلة تتطلب نطاقاً (span) لكل خطوة، وليس رقماً إجمالياً واحداً لكل تشغيل — وهذا بالضبط ما يضيفه تتبع OpenTelemetry فوق رسالة النتيجة، وليس بدلاً منها.

## الخطوة 1: إعداد المشروع

```bash
mkdir agent-observability && cd agent-observability
npm init -y
npm install @anthropic-ai/claude-agent-sdk@0.3.210 zod@4
npm install -D TypeScript@7 @types/node@26
npx tsc --init --target ES2022 --module NodeNext --moduleResolution NodeNext --strict
```

أضف `"type": "module"` إلى `package.json` — حيث يتم شحن SDK نفسه كـ `"type": "module"`، ويتوقع `tsc --moduleResolution NodeNext` أن يتطابق المشروع المستهلك معه[^3].

## الخطوة 2: تفعيل إشارات التتبع الثلاث

[المقاييس، وأحداث السجلات، والتتبعات هي ثلاث إشارات مستقلة، لكل منها مفتاح تصدير خاص، وجميعها متوقفة حتى تقوم بتفعيل المفتاح الرئيسي](#step-2-turn-on-the-three-telemetry-signals)[^1]:

```TypeScript
// otel-env.ts
export const otelEnv = {
  ...process.env,
  // Master switch — nothing exports without this
  CLAUDE_CODE_ENABLE_TELEMETRY: "1",
  // Traces specifically are beta and need this second flag;
  // metrics and log events do not.
  CLAUDE_CODE_ENHANCED_TELEMETRY_BETA: "1",
  OTEL_TRACES_EXPORTER: "otlp",
  OTEL_METRICS_EXPORTER: "otlp",
  OTEL_LOGS_EXPORTER: "otlp",
  OTEL_EXPORTER_OTLP_PROTOCOL: "http/json",
  OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
  OTEL_SERVICE_NAME: "weather-agent-demo",
};
```

هناك أمران من السهل الخطأ فيهما هنا. أولاً، لا تضع `console` كقيمة للمصدر عند التشغيل من خلال SDK — لأن SDK يستخدم stdout كقناة رسائل خاصة به، لذا فإن مخرجات مصدر console ستتداخل مع (وقد تفسد) البروتوكول الذي يقرأه[^1]. بدلاً من ذلك، وجه `OTEL_EXPORTER_OTLP_ENDPOINT` نحو مستقبل محلي حقيقي، وهو بالضبط ما تقوم الخطوة 5 ببنائه.

ثانياً، في TypeScript، أي شيء تمرره كـ `options.env` **يستبدل** بيئة العملية الفرعية بالكامل بدلاً من الدمج معها — تعريف الأنواع الخاص بـ SDK المثبت يوضح ذلك حرفياً: "هذه القيمة تستبدل بيئة العملية الفرعية بالكامل — لا يتم دمجها مع `process.env`"[^4]. لهذا السبب يقوم `otelEnv` أعلاه بنشر `...process.env` أولاً؛ إذا تخطيت ذلك، ستفقد العملية الفرعية `PATH` و `HOME` و `ANTHROPIC_API_KEY`. يتصرف `ClaudeAgentOptions.env` في Python بشكل مختلف — حيث يدمج البيانات فوق البيئة الموروثة بدلاً من استبدالها[^1].

## الخطوة 3: إعطاء العميل أداة تستحق التتبع

استعلام "hello world" من دورة واحدة ينتج فقط نطاق `llm_request` واحد. لرؤية التسلسل الهرمي الكامل — بما في ذلك نطاقات الأدوات — يحتاج العميل إلى استدعاء أداة واحدة على الأقل. هذه أداة طقس بسيطة تم بناؤها باستخدام مساعدات `tool()` و `createSdkMcpServer()` الخاصة بـ SDK:

بربطها في استدعاء `query()` بجانب بيئة القياس عن بُعد (telemetry) من الخطوة 2:

```TypeScript
// index.ts
import { query } from "@anthropic-ai/claude-agent-sdk";
import { otelEnv } from "./otel-env.js";
import { weatherServer } from "./weather-tool.js";

async function main() {
  for await (const message of query({
    prompt: "What's the weather like in Berlin?",
    options: {
      model: "claude-opus-4-8",
      mcpServers: { weather: weatherServer },
      allowedTools: ["mcp__weather__get_weather"],
      env: otelEnv,
    },
  })) {
    if (message.type === "assistant") {
      console.log(message.message.content);
    }
    if (message.type === "result" && message.subtype === "success") {
      console.log("total_cost_usd:", message.total_cost_usd);
      console.log("duration_ms:", message.duration_ms);
    }
  }
}

main();
```

يعمل هذا على Claude Opus 4.8 (`claude-opus-4-8`) — تشير إرشادات Anthropic نفسها إلى "البدء بـ Claude Opus 4.8 للبرمجة الوكيلية المعقدة وأعمال المؤسسات" إذا كنت غير متأكد من النموذج الذي يجب استخدامه[^5].

## الخطوة 4: قراءة شجرة الـ span

مع تفعيل التتبع (tracing)، ينتج عن دورة مستخدم واحدة هذا التسلسل الهرمي — هذه هي الشجرة الموثقة، مأخوذة حرفياً من مرجع المراقبة[^2]:

```text
claude_code.interaction
├── claude_code.llm_request
├── claude_code.hook                    (requires detailed beta tracing)
└── claude_code.tool
    ├── claude_code.tool.blocked_on_user
    ├── claude_code.tool.execution
    └── (Agent tool) subagent claude_code.llm_request / claude_code.tool spans
```

`claude_code.interaction` هو الجذر: واحد لكل دورة مستخدم، ويحمل `user_prompt_length`، و `interaction.sequence`، و `interaction.duration_ms`. أما `claude_code.llm_request` فيغلف كل استدعاء لـ Claude API وهو المكان الذي توجد فيه السمات المتعلقة بالتكلفة وزمن الاستجابة: `model`، و `duration_ms`، و `ttft_ms` (الوقت حتى أول توكن)، و `input_tokens`، و `output_tokens`، و `cache_read_tokens`، و `cache_creation_tokens`، و `stop_reason`، و `success`[^2].

`claude_code.tool` يغلف كل استدعاء للأداة مع `tool_name`، و `duration_ms`، و `result_tokens`، وينقسم إلى اثنين من الأبناء: `claude_code.tool.blocked_on_user` (الوقت المستغرق في انتظار قرار الإذن، مع `decision: accept|reject`) و `claude_code.tool.execution` (التشغيل الفعلي، مع `success`/`error`)[^2]. ثلاثة أنواع فقط من الـ spans تحمل حالة `ERROR` — وهي `llm_request`، و `tool.execution`، و `hook` — وكل شيء آخر ينتهي دائماً بـ `UNSET` حتى عند الفشل، لأن الفشل في تلك الـ spans يتم التعبير عنه من خلال الـ spans الأبناء الخاصة بها بدلاً من ذلك[^2].

`claude_code.hook` حالة خاصة: فهي تتطلب `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1` بالإضافة إلى متغيرين إضافيين، `ENABLE_BETA_TRACING_DETAILED=1` و `BETA_TRACING_ENDPOINT`. في جلسات CLI التفاعلية، تتطلب أيضاً أن تكون مؤسستك مدرجة في القائمة المسموح بها لهذه الميزة — ولكن Agent SDK وجلسات `-p` غير التفاعلية **ليست** مقيدة بشرط القائمة المسموح بها هذا[^2]، لذا فإن الـ hook spans متاحة لمستهلكي SDK اليوم حتى في الأماكن التي لم تتوفر فيها بعد لكل من يستخدم CLI مباشرة.

## هل تتبع هذه الـ spans الاصطلاحات الدلالية لـ OpenTelemetry GenAI؟

جزئياً، ومن الجدير بالذكر أن نكون دقيقين بشأن الأجزاء. *أسماء* الـ spans — `claude_code.interaction`، و `claude_code.llm_request`، و `claude_code.tool` — هي مساحة الأسماء الخاصة بـ Anthropic، وليست مخطط التسمية الخاص باصطلاحات GenAI؛ فالاصطلاحات نفسها تحدد أسماء spans قائمة على العملية بدلاً من ذلك، مثل `invoke_agent` لتشغيل الوكيل، و `chat` لاستدعاء LLM، و `execute_tool` لاستدعاء أداة[^7]. تظل هذه الاصطلاحات في حالة تجريبية/تطويرية اعتباراً من منتصف عام 2026 وقد انتقلت إلى مستودع `semantic-conventions-genai` مخصص، منفصل عن مواصفات OpenTelemetry الرئيسية[^7]. ولكن مجموعة فرعية محددة ومسماة من *السمات (attributes)* في spans الخاصة بـ `claude_code.*` في Claude Agent SDK موثقة صراحةً على أنها تطبق اصطلاح GenAI بغض النظر عن عدم تطابق اسم الـ span:

| Span                              | سمات خاصة بـ Anthropic (أمثلة)                                                                    | سمات الاصطلاح الدلالي لـ OpenTelemetry GenAI                                                                           |
| --------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `claude_code.llm_request`         | `model`, `duration_ms`, `ttft_ms`, `input_tokens`, `output_tokens`, `stop_reason`, `query_source` | `gen_ai.system` (دائماً `"anthropic"`), `gen_ai.request.model`, `gen_ai.response.id`, `gen_ai.response.finish_reasons` |
| `claude_code.tool` / `.execution` | `tool_name`, `result_tokens`, `file_path`, `full_command`                                         | `gen_ai.tool.call.id`                                                                                                  |

المصدر: جداول السمات في مرجع المراقبة، والتي تصنف كل سمة من هذه السمات الخمس على أنها "OpenTelemetry GenAI semantic convention" بشكل فردي[^2]. النتيجة العملية: أي نظام خلفي يعرض لوحات البيانات بناءً على *أسماء* spans اصطلاح GenAI فقط لن يتعرف على `claude_code.llm_request` كعملية GenAI بشكل تلقائي، لأن الاسم نفسه ليس جزءاً من ذلك الاصطلاح — ولكنه سيجد السمات الخمس `gen_ai.*` إذا قام بالاستعلام عن طريق السمة بدلاً من اسم الـ span. لا تفترض الامتثال الكامل، ولا تفترض انعدام العلاقة أيضاً.

إحدى هذه السمات الخمس تستحق تنبيهاً خاصاً: `gen_ai.system` لا تظهر في أي مكان في سجل سمات OpenTelemetry GenAI الحالي — فقد قامت المواصفات منذ ذلك الحين بتغيير اسمها إلى `gen_ai.provider.name` لنفس الغرض وهو "أي مزود تعامل مع هذا الاستدعاء"[^7].

لا تزال وثائق المراقبة الخاصة بـ Anthropic تصنف `gen_ai.system` كسمة اصطلاح GenAI التي يصدرها Claude Code، مما يعني إما أن الـ span الخاص بـ CLI لا يزال يحمل هذا المفتاح حرفياً، أو أن وثائق Anthropic نفسها لم يتم تحديثها إلى اسم السمة الحالي — هذا المنشور ينقل ما تقوله وثائق Anthropic و SDK فعلياً اليوم، وليس ما تطلبه أحدث مراجعة للمواصفات، لذا لا تفترض أن `gen_ai.system` هو اسم المفتاح الذي يتوقعه أي نظام خلفي أو لوحة بيانات GenAI محدثة وفقاً للمواصفات.

إذا كنت تفضل إعداد حلقة استدعاء أدوات يدوية مباشرة وفقاً لاصطلاحات GenAI الحالية — spans `invoke_agent`/`chat`/`execute_tool` و `gen_ai.provider.name` بدلاً من تصدير `claude_code.*` الخاص بـ Agent SDK — فإن [درس تتبع الاصطلاحات الدلالية لـ OpenTelemetry GenAI](https://nerdleveltech.com/opentelemetry-claude-agent-tracing-TypeScript-tutorial) يبني ذلك بالضبط، من Messages API الخام بدلاً من Agent SDK.

## الخطوة 5: رؤية spans حقيقية دون الدفع مقابل نظام خلفي

لست بحاجة إلى Jaeger أو مورد تجاري لفحص ما يرسله CLI فعلياً — خادم HTTP بسيط يقوم بتسجيل جسم الطلب (request body) يفي بالغرض، طالما أنك تستخدم بروتوكول `http/json` (JSON قابل للقراءة) بدلاً من `http/protobuf`:

```TypeScript
// receiver.ts
import http from "node:http";

const server = http.createServer((req, res) => {
  if (req.method === "POST" && req.url === "/v1/traces") {
    let body = "";
    req.on("data", (chunk) => (body += chunk));
    req.on("end", () => {
      const parsed = JSON.parse(body);
      for (const rs of parsed.resourceSpans ?? []) {
        for (const ss of rs.scopeSpans ?? []) {
          for (const span of ss.spans ?? []) {
            console.log(`${span.name}`);
          }
        }
      }
      res.writeHead(200, { "Content-Type": "application/json" });
      res.end("{}");
    });
  } else {
    res.writeHead(404);
    res.end();
  }
});

server.listen(4318, () => {
  console.log("Listening on http://localhost:4318/v1/traces");
});
```

قم بتشغيله مباشرة باستخدام `node receiver.ts` — إصدارات Node 22.18.0 وما بعدها تقوم بتشغيل ملفات TypeScript التي تحتوي على بناءات قابلة للمسح (erasable syntax) مثل هذا الملف بشكل أصلي، دون الحاجة إلى علامة (flag) أو خطوة تجميع. في الإصدارات من Node 22.6.0 إلى 22.17.x، أضف العلامة صراحةً: `node --experimental-strip-types receiver.ts`. الإصدارات الأقدم، بما في ذلك جميع إصدارات Node 18.x و 20.x، لا تدعم تشغيل ملفات `.ts` بشكل أصلي على الإطلاق — استخدم `npx tsx receiver.ts` أو قم بالتجميع باستخدام `tsc` أولاً[^8].

بعد ذلك، قم بتشغيل `index.ts` من الخطوة 3 ضده. بالنسبة للاستخدام في بيئة الإنتاج، استبدل هذا بـ collector فعلي أو حاوية Jaeger شاملة — الإرشادات الرسمية صريحة في أن هذا النوع من المستمعات البسيطة مخصص للفحص المحلي، وليس لتشغيل خط أنابيب حقيقي[^1].

## الخطوة 6: ربط التتبع بـ span الخاص بتطبيقك

```TypeScript
// traced-request.ts
import { trace } from "@opentelemetry/API";
import { query } from "@anthropic-ai/claude-agent-sdk";
import { otelEnv } from "./otel-env.js";

const tracer = trace.getTracer("weather-agent-demo");

export async function handleUserRequest(prompt: string) {
  return tracer.startActiveSpan("handle-user-request", async (span) => {
    try {
      for await (const message of query({
        prompt,
        options: { model: "claude-opus-4-8", env: otelEnv },
      })) {
        if (message.type === "result" && message.subtype === "success") {
          span.setAttribute("total_cost_usd", message.total_cost_usd);
        }
      }
    } finally {
      span.end();
    }
  });
}
```

يتم تخطي الحقن التلقائي إذا قمت بتعيين `TRACEPARENT` صراحةً في `options.env` بنفسك — وهذا مفيد إذا كنت بحاجة إلى تثبيت سياق أب محدد بدلاً من أي span نشط حالياً. تتجاهل جلسات CLI التفاعلية `TRACEPARENT` الواردة تماماً لتجنب التقاط قيم محيطة من CI أو الحاويات؛ فقط تشغيل Agent SDK و `claude -p` هما من يلتزمان بها[^1][^2]. هناك حد للنطاق آخر يستحق المعرفة: يتم إرسال رأس `traceparent` إلى Anthropic API مباشرة بشكل افتراضي. إذا كنت تقوم بالتوجيه عبر بروكسي `ANTHROPIC_BASE_URL` مخصص، فإن الانتشار (propagation) يكون متوقفاً ما لم تقم أيضاً بتعيين `CLAUDE_CODE_PROPAGATE_TRACEPARENT=1`، لأن بعض البروكسيات ترفض الرؤوس غير المعروفة[^2].

## الخطوة 7: وسم التتبعات حسب الخدمة والمستخدم والمستأجر

الاسم الافتراضي لـ `service.name` في كل span هو `claude-code`[^1]. إذا كان هناك أكثر من عميل (agent) في نظامك يقوم بالتصدير إلى نفس الـ collector، قم بتجاوزه وإرفاق أي بيانات وصفية تحتاجها للتصفية بها لاحقاً:

```TypeScript
const options = {
  env: {
    ...otelEnv,
    OTEL_SERVICE_NAME: "support-triage-agent",
    OTEL_RESOURCE_ATTRIBUTES:
      `service.version=1.4.0,deployment.environment=production,enduser.id=${encodeURIComponent(userId)},tenant.id=${encodeURIComponent(tenantId)}`,
  },
};
```

قم بتشفير قيم السمات بنسبة مئوية (Percent-encode) قبل دمجها — حيث يحتفظ `OTEL_RESOURCE_ATTRIBUTES` بالفواصل والمسافات وعلامات التساوي كمحددات خاصة به[^1]. مع إرفاق `enduser.id`/`tenant.id`، تصبح أحداث السجل الخاصة بـ `tool_decision` و `tool_result` و `mcp_server_connection` و `permission_mode_changed` بمثابة سجل مراجعة لكل مستخدم يمكنك توجيهه إلى SIEM، بدلاً من مجرد نسب كل إجراء إلى أي بيانات اعتماد تعمل تحتها العملية[^1].

## التحكم فيما يتم التقاطه

تكون الـ spans هيكلية بشكل افتراضي — يتم دائماً تسجيل المدد وأسماء النماذج وأسماء الأدوات، ولكن لا يتم تسجيل عدد التوكنات إلا عندما تعيد مكالمة API الأساسية بيانات الاستخدام فعلياً (لذا قد يخلو span الخاص بطلب فاشل أو ملغى منها ببساطة)، ولا يتم أبداً التقاط *المحتوى* الذي يقرأه ويكتبه العميل الخاص بك إلا إذا اخترت ذلك[^1][^2]:

| المتغير                   | ما الذي يضيفه                                                                                                                           |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `OTEL_LOG_USER_PROMPTS=1` | نص المطالبة (Prompt) في سمة `user_prompt` الخاصة بـ span الـ `claude_code.interaction`                                                  |
| `OTEL_LOG_TOOL_DETAILS=1` | وسائط إدخال الأداة — مسارات الملفات، أوامر shell، أنماط البحث — في `claude_code.tool`                                                   |
| `OTEL_LOG_TOOL_CONTENT=1` | أجسام إدخال/إخراج الأداة الكاملة كحدث span، يتم قصها عند 60 كيلوبايت؛ تتطلب أن يكون التتبع مفعلاً بالفعل                                |
| `OTEL_LOG_RAW_API_BODIES` | JSON كامل لطلب/استجابة Messages API؛ القيمة `1` تقص المحتوى داخلياً عند 60 كيلوبايت، و `file:<dir>` تكتب الأجسام غير المقصوصة على القرص |

اترك المتغيرات الأربعة بدون تعيين ما لم يكن خط أنابيب المراقبة الخاص بك معتمداً خصيصاً لتخزين ما يتعامل معه العميل الخاص بك — تفعيل متغير الأجسام الخام (raw-bodies) يعني الموافقة على كل ما قد تكشفه المتغيرات الثلاثة الأخرى بشكل منفصل[^1].

## إرسال التتبعات إلى backend حقيقي

هناك مساران مختلفان تماماً يوصلانك إلى لوحة تحكم، وهما يقومان بتجهيز أشياء مختلفة:

|                                 | تصدير CLI الأصلي (هذا البرنامج التعليمي)                                                         | تجهيز OpenInference                                                                                        |
| ------------------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
| ما الذي يتم تجهيزه فعلياً       | العملية الفرعية لـ Claude Code CLI التي يقوم الـ SDK بتشغيلها                                    | مكالمات SDK الخاصة بعمليتك، والتي يتم تعديلها بواسطة مكتبة تجهيز JS/Python                                 |
| أسماء الـ spans التي تحصل عليها | `claude_code.*`                                                                                  | شكل span الخاص بـ OpenInference                                                                            |
| الحزم الإضافية المطلوبة         | لا يوجد — فقط متغيرات البيئة                                                                     | `@arizeai/openinference-instrumentation-claude-agent-sdk`, `@langfuse/otel`, `@opentelemetry/sdk-node`[^6] |
| أين يمكن أن تذهب                | أي backend متوافق مع OTLP: Honeycomb, Datadog, Grafana, collector مستضاف ذاتياً، أو Langfuse[^1] | أي exporter تربط به الـ `NodeSDK` — توضح وثائق Langfuse هذا المسار تحديداً[^6]                             |

مسار OpenInference (المستخدم في تكامل JS/TS الرسمي لـ Langfuse) هو طبقة تجهيز مجتمعية منفصلة، وليس تكويناً بديلاً لنفس التصدير على مستوى CLI الذي يبنيه هذا البرنامج التعليمي — يمكن للاثنين التعايش، ولكن لا تتوقع منهما إنتاج أشجار span متطابقة[^6]. إذا كان هدفك هو مراجعة المطالبات/الاستجابات، والتقييم، وتنسيق مجموعات البيانات، فإن مسار OpenInference-to-Langfuse مصمم لذلك. أما إذا كان هدفك هو لوحات تحكم بأسلوب العمليات (ops)، أو توزيع التكاليف لكل مستأجر، أو سجل مراجعة قابل للتوجيه إلى SIEM، فإن تصدير CLI الأصلي الذي يغطيه هذا البرنامج التعليمي هو المسار الأكثر مباشرة، لأنه لا يتطلب إضافة تبعية تجهيز إلى عمليتك على الإطلاق.

## التكلفة وزمن الاستجابة بدون كل هذا

إذا كان كل ما تحتاجه هو رقم واحد لكل عملية تشغيل، فأنت لست بحاجة إلى OpenTelemetry على الإطلاق. رسالة `result` في تدفق استجابة الـ SDK نفسه تحمل بالفعل `total_cost_usd` و `duration_ms` و `num_turns` وتفصيلاً كاملاً لـ `usage`/`modelUsage` لمكالمة `query()` بالكامل، دون الحاجة إلى أي تكوين للمصدر (exporter)[^4]. التتبع مخصص للحالات التي لا يكون فيها هذا الرقم الإجمالي كافياً لمعرفة *أي خطوة* كانت مكلفة — الاثنان يكملان بعضهما البعض ولا يتنافسان، ودليل المراقبة الخاص بـ Anthropic يربط بوثيقة تتبع التكاليف لهذا السبب تحديداً[^1].

## التحقق

**ما تم تشغيله فعلياً:** تم تثبيت كل عينة كود أعلاه مقابل الإصدار الحقيقي والمنشور حالياً `@anthropic-ai/claude-agent-sdk@0.3.210` (سجل npm، تم التأكد في 2026-07-15) بالإضافة إلى `zod@4.4.3`، و `@types/node@26.1.1`، و `TypeScript@7.0.2`، و `@opentelemetry/API@1.9.1`، وتم فحص الأنواع باستخدام `tsc --strict --target es2022 --module nodenext --moduleResolution nodenext`. جميع ملفات TypeScript الخمسة — `otel-env.ts`، و `weather-tool.ts`، و `index.ts`، و `traced-request.ts`، و `receiver.ts` — تم تجميعها معاً دون أي أخطاء. تم تشغيل خادم `receiver.ts` فعلياً (`node`، يستمع على المنفذ 4318) وأرسل حمولة OTLP/JSON مصممة يدوياً عبر `curl` تحتوي على أسماء الـ spans الحقيقية من الخطوة 4؛ وقام المستقبل بتحليلها بشكل صحيح وطبع جميع أسماء الـ spans الثلاثة، مما يؤكد أن منطق التحليل يعمل مقابل شكل الحمولة الموثق.

**ما لم يتم تشغيله:** استدعاء `query()` مباشر مقابل API الحقيقي لـ Claude. يتطلب ذلك `ANTHROPIC_API_KEY` مدفوع، وهو ما لا يملك خط أنابيب الكتابة الآلي هذا وصولاً إليه، لذا لم يتم التقاط أي spans حقيقية لـ `claude_code.*` من تشغيل وكيل فعلي — شجرة الـ spans وأسماء السمات في هذا المنشور منقولة مباشرة من المرجع الموثق الخاص بـ Anthropic، وليس من عملية التقاط مستقلة[^2]. إذا كان لديك مفتاح، قم بتشغيل:

```bash
export ANTHROPIC_API_KEY=sk-ant-...
npx tsx index.ts
```

يجب أن ترى إجابة الطقس مطبوعة، تليها `total_cost_usd` و `duration_ms` من رسالة `result`، و — إذا كان `receiver.ts` يعمل و `OTEL_EXPORTER_OTLP_ENDPOINT` يشير إليه — سطر `claude_code.interaction` تتبعه أسطر `claude_code.llm_request` و `claude_code.tool` في وحدة تحكم المستقبل نفسها.

## استكشاف الأخطاء وإصلاحها

**لا تصل أي spans إلى أي مكان.** تأكد من ضبط كل من `CLAUDE_CODE_ENABLE_TELEMETRY=1` و `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1` — تتطلب التتبعات (traces) كليهما، على عكس المقاييس والسجلات التي تتطلب الأول فقط[^1][^2].

**تصل الـ spans ولكن كل سمة كنت تتوقعها مفقودة.** التقاط المحتوى اختياري. إذا كانت `user_prompt`، أو مدخلات الأداة، أو أجسام الأدوات مفقودة، فهذا هو سلوك التعتيم الافتراضي وليس خطأً — قم بضبط متغير `OTEL_LOG_*` ذو الصلة من الجدول أعلاه[^1].

**لا يظهر شيء في `stdout`، أو يبدو أن العملية تتوقف بشكل غريب.** تأكد من أنك لم تضبط `console` كقيمة للمصدر (exporter) — يستخدم الـ SDK بالفعل stdout كقناة رسائل، وسيحدث تصادم بينهما[^1].

**التتبعات لا تتداخل تحت الـ span الخاص بتطبيقي.** تأكد من أن الـ span الخاص بك *نشط* فعلياً (عبر `startActiveSpan`، وليس مجرد إنشائه) في اللحظة التي يتم فيها استدعاء `query()`، وأنك لم تضبط `TRACEPARENT` صراحةً في `options.env`، مما يتجاوز الحقن التلقائي بالكامل[^1].

**كل ما سبق يعمل محلياً ولكن لا يصل شيء عند التوجيه عبر URL أساسي مخصص.** إذا كان `ANTHROPIC_BASE_URL` يشير إلى أي شيء آخر غير API الخاص بـ Anthropic مباشرة، فقم بضبط `CLAUDE_CODE_PROPAGATE_TRACEPARENT=1` — حيث يكون التمرير إلى نقاط النهاية غير التابعة لـ Anthropic معطلاً بشكل افتراضي[^2].

## الأسئلة الشائعة

### هل تتبع Claude Agent SDK مستقر؟

لا. تم توثيقه صراحةً على أنه نسخة تجريبية (beta) — قد تتغير أسماء الـ spans والسمات بين إصدارات الـ SDK، وهذا هو السبب أيضاً في حاجته إلى علامة `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA` الخاصة به منفصلة عن المقاييس والسجلات[^1][^2].

### هل تستخدم تتبعات Claude Agent SDK الاصطلاحات الدلالية لـ OpenTelemetry GenAI؟

جزئياً. تم توثيق خمس سمات محددة (`gen_ai.system`، و `gen_ai.request.model`، و `gen_ai.response.id`، و `gen_ai.response.finish_reasons`، و `gen_ai.tool.call.id`) على أنها تطبق هذا الاصطلاح. أما أسماء الـ spans ومعظم السمات الأخرى فتستخدم نطاق `claude_code.*` الخاص بـ Anthropic بدلاً من ذلك، ولا تزال اصطلاحات GenAI نفسها في حالة تجريبية اعتباراً من منتصف عام 2026[^2][^7].

### هل يمكنني رؤية التتبعات دون الدفع لمزود مراقبة تجاري؟

نعم. قم بتوجيه `OTEL_EXPORTER_OTLP_ENDPOINT` إلى حاوية Jaeger محلية مجانية، أو إلى المستقبل المخصص البسيط الذي تم بناؤه في الخطوة 5، أو إلى Langfuse — حيث أن الفئة السحابية للهواة (Hobby) مجانية ولا تتطلب بطاقة ائتمان، كما أن إصدار المجتمع (Community) المستضاف ذاتياً مجاني أيضاً ومرخص بموجب MIT، مع تضمين الميزات الأساسية للمراقبة والتقييم وإدارة المطالبات[^1][^6][^9].

### هل يلتقط التتبع مطالباتي ومدخلات الأدوات بشكل افتراضي؟

لا. يتم تسجيل المدد الزمنية وأسماء النماذج وأسماء الأدوات بشكل افتراضي؛ أما نص المطالبة الفعلي ومحتوى مدخلات/مخرجات الأداة فيتطلب ضبط `OTEL_LOG_USER_PROMPTS`، أو `OTEL_LOG_TOOL_DETAILS`، أو `OTEL_LOG_TOOL_CONTENT` صراحةً[^1][^2].

### كيف يختلف هذا عن تتبع التكاليف المدمج في الـ SDK؟

تعطيك رسالة `result` رقماً واحداً لـ `total_cost_usd` لكل استدعاء `query()`، دون أي إعدادات. أما التتبع فيقوم بتفصيل هذه التكلفة وزمن الاستجابة لكل طلب نموذج ولكل استدعاء أداة، بحيث يمكنك معرفة أي خطوة محددة في عملية متعددة الخطوات كانت مكلفة[^4].

### هل يعمل أي من هذا بنفس الطريقة في Python؟

نعم في الغالب — يتم تطبيق نفس متغيرات البيئة ونفس شجرة نطاق `claude_code.*`، بما أن كلا الـ SDKs للغات البرمجة يشغلان نفس واجهة سطر أوامر Claude Code الأساسية. الفرق الملموس الوحيد هو أن `ClaudeAgentOptions.env` في Python يدمج الإعدادات فوق البيئة الموروثة، بينما TypeScript's `options.env` يستبدلها بالكامل[^1].

## الخطوات التالية وقراءات إضافية

يتتبع هذا البرنامج التعليمي الأدوات المدمجة والأدوات المحددة بواسطة SDK؛ وتطبق نفس نطاقات `claude_code.tool` على الأدوات المعروضة عبر MCP، وهو أمر يستحق الدمج مع [البرنامج التعليمي لخادم MCP في بيئة الإنتاج مع OAuth و HTTP القابل للبث](https://nerdleveltech.com/mcp-server-TypeScript-oauth-streamable-http-production-tutorial) إذا كانت أدوات العميل الخاص بك تقع خلف نقطة نهاية MCP موثقة.

إذا كنت تقوم أيضًا بإضافة طبقة موافقة أمام استدعاءات الأدوات، فإن [البرنامج التعليمي لـ Claude Agent SDK بنظام "الإنسان في الحلقة" (human-in-the-loop)](https://nerdleveltech.com/human-in-the-loop-claude-agent-sdk-TypeScript-tutorial) يغطي استدعاء `canUseTool` وخطافات `PreToolUse`/`PostToolUse` لبناء سجل تدقيق خاص بك — وهي آلية مختلفة عن حدث سجل `tool_decision` الذي يغطيه قسم مسار التدقيق في هذا المنشور، لأن ذلك الحدث يتم إصداره تلقائيًا بمجرد تفعيل `OTEL_LOGS_EXPORTER` بدلاً من كتابته بواسطة خطاف تقوم بتطويره بنفسك، ولكن المكانين يكملان بعضهما البعض للبحث عن نفس النوع من سجلات "ماذا فعل العميل فعليًا".

وإذا كان العميل الخاص بك بحاجة إلى تذكر الأشياء عبر الجلسات بدلاً من مجرد أن يكون قابلاً للملاحظة داخل جلسة واحدة، فإن [البرنامج التعليمي لأداة ذاكرة Claude وتحرير السياق](https://nerdleveltech.com/claude-memory-tool-context-editing-TypeScript-tutorial) يغطي ميزة الذاكرة المستمرة في SDK، وهي مسألة تتعلق بحزمة مختلفة تمامًا عن إعداد التتبع هنا.

[^1]: Anthropic, "Observability with OpenTelemetry" — <https://code.claude.com/docs/en/agent-sdk/observability> (نموذج الإشارات الثلاث، أعلام `CLAUDE_CODE_ENABLE_TELEMETRY`/`CLAUDE_CODE_ENHANCED_TELEMETRY_BETA`، سلوك الاستبدال مقابل الدمج في TypeScript `env`، انتشار سياق تتبع W3C، `OTEL_SERVICE_NAME`/`OTEL_RESOURCE_ATTRIBUTES`، متغيرات الموافقة على التقاط المحتوى؛ تم الجلب في 2026-07-15)

[^2]: Anthropic, "Monitoring" — <https://code.claude.com/docs/en/monitoring-usage>، قسم "Traces (beta)" (مخطط التسلسل الهرمي للـ span، جداول سمات كل span، سمات `gen_ai.*` المصنفة فرديًا كـ "OpenTelemetry GenAI semantic convention"، نطاق القائمة المسموح بها لـ `claude_code.hook`، `CLAUDE_CODE_PROPAGATE_TRACEPARENT`، دلالات حالة OTel؛ تم الجلب في 2026-07-15)

[^3]: npm registry, `@anthropic-ai/claude-agent-sdk` — <https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk> (الإصدار 0.3.210، نُشر في 2026-07-14T19:39:19.351Z وفقًا لإدخال `time` الخاص بسجل هذا الإصدار، `engines.node >=18.0.0`، إصدار `claudeCodeVersion` المدمج 2.1.210، التبعيات الموازية peerDependencies `zod ^4.0.0`/`@anthropic-ai/sdk >=0.93.0`/`@modelcontextprotocol/sdk ^1.29.0`؛ تم الجلب مباشرة من السجل API، 2026-07-15)

[^4]: تعريفات الأنواع المجمعة لـ `@anthropic-ai/claude-agent-sdk@0.3.210`، `sdk.d.ts` — تم التثبيت من npm والفحص مباشرة، 2026-07-15 (تعليق دلالات الاستبدال لـ `Options.env`، توقيعات `query()`/`tool()`/`createSdkMcpServer()`، حقول `SDKResultSuccess` بما في ذلك `total_cost_usd`/`duration_ms`/`usage`/`modelUsage`)

[^5]: Anthropic, "Models overview" — <https://platform.claude.com/docs/en/about-claude/models/overview> (معرفات النماذج الحالية والأسعار: Claude Opus 4.8 `claude-opus-4-8` بسعر 5$/25$ لكل مليون توكن؛ تم الجلب في 2026-07-15)

[^7]: OpenTelemetry, "Generative AI semantic conventions" — <https://opentelemetry.io/docs/specs/semconv/gen-ai/> (تنص الصفحة صراحةً على أن اتفاقيات GenAI الدلالية قد انتقلت إلى مستودع `semantic-conventions-genai` مخصص ولم تعد تُصان في مستودع المواصفات الرئيسي؛ تم الجلب في 2026-07-15). تم تأكيد حالة التطوير/التجريبية وقت كتابة هذا النص بشكل منفصل عبر منشور مدونة OpenTelemetry، "GenAI observability"، بتاريخ 14 مايو 2026 — <https://opentelemetry.io/blog/2026/genai-observability/> ("قيد التطوير النشط")، وعبر أسماء الـ span مثل `invoke_agent`/`chat`/`execute_tool` التي يوثقها منشور المدونة كـ "مخطط تسمية" خاص باتفاقيات GenAI — وهو متميز عن `claude_code.*`. جدول السمات الكامل في نفس صفحة السجل (تم الجلب مباشرة، 2026-07-15) يسرد `gen_ai.provider.name` ولكن لا يحتوي على أي إدخال لـ `gen_ai.system` مجردة في أي مكان، سواء أبجديًا أو غير ذلك — فقط تظهر سمة `gen_ai.system_instructions` المتميزة — وهو ما يتفق مع إعادة تسمية `gen_ai.system` إلى `gen_ai.provider.name` في المواصفات الحالية.

[^8]: Node.js, "Running TypeScript Natively" — <https://nodejs.org/learn/TypeScript/run-natively> (الإصدار v22.18.0+ يشغل ملفات `.ts` ذات القواعد القابلة للمسح بدون أي flag؛ الإصدارات الأقدم تحتاج إلى `--experimental-strip-types`؛ عملية تجريد الأنواع لا تقوم بفحص الأنواع، ولا يتم دعم `enum`/namespaces/parameter properties؛ تم الجلب في 2026-07-15)

[^6]: Langfuse, "Observability for Claude Agent SDK JS/TS with Langfuse" — <https://langfuse.com/integrations/frameworks/claude-agent-sdk-js> (قائمة أوامر التثبيت تشمل `@anthropic-ai/claude-agent-sdk`، و `@arizeai/openinference-instrumentation-claude-agent-sdk`، و `@langfuse/otel`، و `@opentelemetry/sdk-node` معاً؛ إعداد `NodeSDK`/`LangfuseSpanProcessor`؛ المثال القابل للتشغيل الموجود على الصفحة هو عبارة عن prompt بدون أدوات على `claude-sonnet-4-5`، وليس أداة طقس؛ تم الجلب في 2026-07-15)

[^9]: Langfuse, "Pricing" — <https://langfuse.com/pricing> ("خطة Hobby مجانية تماماً ولا تتطلب بطاقة ائتمان،" تشمل 100 ألف وحدة/شهر) و Langfuse, "Self-Hosted Pricing" — <https://langfuse.com/pricing-self-host> (مستوى Community مدرج كـ "مجاني"، رخصة MIT، "جميع ميزات المنصة الأساسية و APIs"؛ تم جلب كليهما مباشرة، 2026-07-15)
