{"meta":{"title":"Copilot SDK 的 OpenTelemetry 检测","intro":"本指南演示如何将 OpenTelemetry 跟踪添加到 Copilot SDK 应用程序。","product":"GitHub Copilot","breadcrumbs":[{"href":"/zh/copilot","title":"GitHub Copilot"},{"href":"/zh/copilot/how-tos","title":"操作方法"},{"href":"/zh/copilot/how-tos/copilot-sdk","title":"Copilot SDK"},{"href":"/zh/copilot/how-tos/copilot-sdk/observability","title":"可观察性"},{"href":"/zh/copilot/how-tos/copilot-sdk/observability/opentelemetry","title":"Opentelemetry"}],"documentType":"article"},"body":"# Copilot SDK 的 OpenTelemetry 检测\n\n本指南演示如何将 OpenTelemetry 跟踪添加到 Copilot SDK 应用程序。\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n## 内置遥测支持\n\nSDK 内置支持在 CLI 进程中配置 OpenTelemetry，并在 SDK 和 CLI 之间传播 W3C 跟踪上下文。 创建客户端时提供 `TelemetryConfig` 以选择启用该功能：\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n<!-- docs-validate: skip -->\n\n```typescript\nimport { CopilotClient } from \"@github/copilot-sdk\";\n\nconst client = new CopilotClient({\n  telemetry: {\n    otlpEndpoint: \"http://localhost:4318\",\n  },\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n<!-- docs-validate: skip -->\n\n```python\nfrom copilot import CopilotClient\n\nclient = CopilotClient(\n    telemetry={\n        \"otlp_endpoint\": \"http://localhost:4318\",\n    },\n)\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n<!-- docs-validate: skip -->\n\n```golang\nclient := copilot.NewClient(&copilot.ClientOptions{\n    Telemetry: &copilot.TelemetryConfig{\n        OTLPEndpoint: \"http://localhost:4318\",\n    },\n})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n<!-- docs-validate: skip -->\n\n```csharp\nvar client = new CopilotClient(new CopilotClientOptions\n{\n    Telemetry = new TelemetryConfig\n    {\n        OtlpEndpoint = \"http://localhost:4318\",\n    },\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n<!-- docs-validate: skip -->\n\n```java\nimport com.github.copilot.CopilotClient;\nimport com.github.copilot.rpc.*;\n\nvar client = new CopilotClient(new CopilotClientOptions()\n    .setTelemetry(new TelemetryConfig()\n        .setOtlpEndpoint(\"http://localhost:4318\"))\n);\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"rust\" data-label=\"Rust\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Rust</div>\n\n<!-- docs-validate: skip -->\n\n```rust\nuse github_copilot_sdk::{Client, ClientOptions, TelemetryConfig};\n\nlet client = Client::start(ClientOptions::new()\n    .with_telemetry(TelemetryConfig::new()\n        .with_otlp_endpoint(\"http://localhost:4318\"))\n).await?;\n```\n\n</div>\n\n</div>\n\n### TelemetryConfig 选项\n\n| 选项                       | Node.js          | Python            | Go               | .NET             | Java             | Rust              | 说明                                                    |\n| ------------------------ | ---------------- | ----------------- | ---------------- | ---------------- | ---------------- | ----------------- | ----------------------------------------------------- |\n| OTLP 终结点                 | `otlpEndpoint`   | `otlp_endpoint`   | `OTLPEndpoint`   | `OtlpEndpoint`   | `otlpEndpoint`   | `otlp_endpoint`   | OTLP HTTP 终结点 URL                                     |\n| OTLP 协议                  | `otlpProtocol`   | `otlp_protocol`   | `OTLPProtocol`   | `OtlpProtocol`   | `otlpProtocol`   | `otlp_protocol`   | 所有信号的 OTLP HTTP 协议： `\"http/json\"` 或 `\"http/protobuf\"` |\n| 文件路径                     | `filePath`       | `file_path`       | `FilePath`       | `FilePath`       | `filePath`       | `file_path`       | JSON 行跟踪输出的文件路径                                       |\n| 导出程序类型                   | `exporterType`   | `exporter_type`   | `ExporterType`   | `ExporterType`   | `exporterType`   | `exporter_type`   |                                                       |\n| `\"otlp-http\"` 或 `\"file\"` |                  |                   |                  |                  |                  |                   |                                                       |\n| 源名称                      | `sourceName`     | `source_name`     | `SourceName`     | `SourceName`     | `sourceName`     | `source_name`     | 仪器范围名称                                                |\n| 捕获内容                     | `captureContent` | `capture_content` | `CaptureContent` | `CaptureContent` | `captureContent` | `capture_content` | 是否捕获消息内容                                              |\n\nOTLP 协议字段用于为所有信号配置 CLI 的 `\"otlp-http\"` 导出器。 将其保留为未设置以使用 CLI 默认值，或将其设置为 `\"http/protobuf\"` 通过 HTTP 导出 protobuf。\n\n### 跟踪上下文传播\n\n> **大多数用户不需要这样做。** 以上 `TelemetryConfig` 是从 CLI 收集跟踪信息的全部所需。 本节中所述的跟踪上下文传播是一项 **高级功能** ，适用于创建自己的 OpenTelemetry 范围的应用程序，并希望它们与 CLI 跨度出现在 **相同的分布式跟踪** 中。\n\nSDK 可以在 JSON-RPC 有效负载上传播 W3C 跟踪上下文（`traceparent`/`tracestate`），以便应用程序范围和 CLI 跨度链接在一个分布式跟踪中。 例如，当你希望在应用中看到“处理工具调用”的 span 嵌套在 CLI 的“执行工具” span 内，或者将 SDK 调用显示为请求处理 span 的子 span 时，这会非常有用。\n\n要沿跟踪进行成本归属，请订阅 `assistant.usage` 事件并检查 `apiEndpoint` (`AssistantUsageApiEndpoint`) 以查看轮次是否使用了 Chat Completions、Responses 或 Anthropic Messages；请参阅 [流式处理会话事件](/zh/copilot/how-tos/copilot-sdk/features/streaming-events)。\n\n#### SDK → CLI（出站）\n\n对于 **Node.js**，请在 `onGetTraceContext` 客户端选项中提供回调函数。 仅当应用程序已使用 `@opentelemetry/api` 并且想要将范围与 CLI 的跨度链接时，才需要这样做。 SDK 在 `session.create`、`session.resume` 和 `session.send` RPC 前调用此回调：\n\n<!-- docs-validate: skip -->\n\n```typescript\nimport { CopilotClient } from \"@github/copilot-sdk\";\nimport { propagation, context } from \"@opentelemetry/api\";\n\nconst client = new CopilotClient({\n  telemetry: { otlpEndpoint: \"http://localhost:4318\" },\n  onGetTraceContext: () => {\n    const carrier: Record<string, string> = {};\n    propagation.inject(context.active(), carrier);\n    return carrier; // { traceparent: \"00-...\", tracestate: \"...\" }\n  },\n});\n```\n\n对于 **Python**、**Go** 和 **.NET**，当配置相应的 OpenTelemetry/Activity API 时，跟踪上下文注入是自动的，无需回调。\n\n#### CLI → SDK（传入）\n\n当 CLI 调用工具处理程序时，CLI 的 span 中的 `traceparent` 和 `tracestate` 在所有语言中都可用：\n\n* **Go**：`ToolInvocation.TraceContext` 字段是一个已恢复追踪的 `context.Context`，可直接将其用作你自定义跨度的父级。\n* **Python**：通过 `trace_context()` 在处理程序周围自动回复跟踪上下文，子跨度会自动以 CLI 的跨度作为父级。\n* **.NET**：通过 `RestoreTraceContext()` 动恢复追踪上下文，子 `Activity` 实例会自动以 CLI 的跨度作为父级。\n* **Node.js**：由于 SDK 没有 OpenTelemetry 依赖，`traceparent` 和 `tracestate` 会作为原始字符串通过 `ToolInvocation` 对象传递。 如果需要，请手动还原上下文：\n\n<!-- docs-validate: skip -->\n\n```typescript\nimport { defineTool } from \"@github/copilot-sdk\";\nimport { propagation, context, trace } from \"@opentelemetry/api\";\n\nconst myTool = defineTool(\"my-tool\", {\n  description: \"Do work\",\n  handler: async (args, invocation) => {\n    // Restore the CLI's trace context as the active context\n    const carrier = {\n      traceparent: invocation.traceparent,\n      tracestate: invocation.tracestate,\n    };\n    const parentCtx = propagation.extract(context.active(), carrier);\n\n    // Create a child span under the CLI's span\n    const tracer = trace.getTracer(\"my-app\");\n    return context.with(parentCtx, () =>\n      tracer.startActiveSpan(\"my-tool\", async (span) => {\n        try {\n          const result = await doWork(args);\n          return result;\n        } finally {\n          span.end();\n        }\n      })\n    );\n  },\n});\n\n// Tool handlers are registered when the session is created.\nconst session = await client.createSession({ tools: [myTool] });\n```\n\n### 每种语言的依赖项\n\n| 语言      | 依赖项                                  | 笔记                                                            |\n| ------- | ------------------------------------ | ------------------------------------------------------------- |\n| Node.js | —                                    | 无依赖项；为出站传播提供 `onGetTraceContext` 回调函数                         |\n| Python  | `opentelemetry-api`                  | 利用 `pip install copilot-sdk[telemetry]` 进行安装                  |\n| Go      | `go.opentelemetry.io/otel`           | 必需的依赖项                                                        |\n| .NET    | —                                    | 使用内置 `System.Diagnostics.Activity`                            |\n| Java    | `io.opentelemetry:opentelemetry-api` | 为基于 SDK 的设置添加此依赖项;配置 OpenTelemetry Java 代理或 SDK 时，跟踪上下文注入是自动的 |\n\n## References\n\n* [OpenTelemetry GenAI 语义约定](https://opentelemetry.io/docs/specs/semconv/gen-ai/)\n* [OpenTelemetry MCP 语义约定](https://opentelemetry.io/docs/specs/semconv/gen-ai/mcp/)\n* [OpenTelemetry Python SDK](https://opentelemetry.io/docs/instrumentation/python/)\n* [Copilot SDK 文档](https://github.com/github/copilot-sdk)"}