# Copilot SDK 的 OpenTelemetry 检测

本指南演示如何将 OpenTelemetry 跟踪添加到 Copilot SDK 应用程序。

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

## 内置遥测支持

SDK 内置支持在 CLI 进程中配置 OpenTelemetry，并在 SDK 和 CLI 之间传播 W3C 跟踪上下文。 创建客户端时提供 `TelemetryConfig` 以选择启用该功能：

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

<!-- docs-validate: skip -->

```typescript
import { CopilotClient } from "@github/copilot-sdk";

const client = new CopilotClient({
  telemetry: {
    otlpEndpoint: "http://localhost:4318",
  },
});
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

<!-- docs-validate: skip -->

```python
from copilot import CopilotClient

client = CopilotClient(
    telemetry={
        "otlp_endpoint": "http://localhost:4318",
    },
)
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

<!-- docs-validate: skip -->

```golang
client := copilot.NewClient(&copilot.ClientOptions{
    Telemetry: &copilot.TelemetryConfig{
        OTLPEndpoint: "http://localhost:4318",
    },
})
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

<!-- docs-validate: skip -->

```csharp
var client = new CopilotClient(new CopilotClientOptions
{
    Telemetry = new TelemetryConfig
    {
        OtlpEndpoint = "http://localhost:4318",
    },
});
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

<!-- docs-validate: skip -->

```java
import com.github.copilot.CopilotClient;
import com.github.copilot.rpc.*;

var client = new CopilotClient(new CopilotClientOptions()
    .setTelemetry(new TelemetryConfig()
        .setOtlpEndpoint("http://localhost:4318"))
);
```

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

<!-- docs-validate: skip -->

```rust
use github_copilot_sdk::{Client, ClientOptions, TelemetryConfig};

let client = Client::start(ClientOptions::new()
    .with_telemetry(TelemetryConfig::new()
        .with_otlp_endpoint("http://localhost:4318"))
).await?;
```

</div>

</div>

### TelemetryConfig 选项

| 选项                       | Node.js          | Python            | Go               | .NET             | Java             | Rust              | 说明                                                    |
| ------------------------ | ---------------- | ----------------- | ---------------- | ---------------- | ---------------- | ----------------- | ----------------------------------------------------- |
| OTLP 终结点                 | `otlpEndpoint`   | `otlp_endpoint`   | `OTLPEndpoint`   | `OtlpEndpoint`   | `otlpEndpoint`   | `otlp_endpoint`   | OTLP HTTP 终结点 URL                                     |
| OTLP 协议                  | `otlpProtocol`   | `otlp_protocol`   | `OTLPProtocol`   | `OtlpProtocol`   | `otlpProtocol`   | `otlp_protocol`   | 所有信号的 OTLP HTTP 协议： `"http/json"` 或 `"http/protobuf"` |
| 文件路径                     | `filePath`       | `file_path`       | `FilePath`       | `FilePath`       | `filePath`       | `file_path`       | JSON 行跟踪输出的文件路径                                       |
| 导出程序类型                   | `exporterType`   | `exporter_type`   | `ExporterType`   | `ExporterType`   | `exporterType`   | `exporter_type`   |                                                       |
| `"otlp-http"` 或 `"file"` |                  |                   |                  |                  |                  |                   |                                                       |
| 源名称                      | `sourceName`     | `source_name`     | `SourceName`     | `SourceName`     | `sourceName`     | `source_name`     | 仪器范围名称                                                |
| 捕获内容                     | `captureContent` | `capture_content` | `CaptureContent` | `CaptureContent` | `captureContent` | `capture_content` | 是否捕获消息内容                                              |

OTLP 协议字段用于为所有信号配置 CLI 的 `"otlp-http"` 导出器。 将其保留为未设置以使用 CLI 默认值，或将其设置为 `"http/protobuf"` 通过 HTTP 导出 protobuf。

### 跟踪上下文传播

> **大多数用户不需要这样做。** 以上 `TelemetryConfig` 是从 CLI 收集跟踪信息的全部所需。 本节中所述的跟踪上下文传播是一项 **高级功能** ，适用于创建自己的 OpenTelemetry 范围的应用程序，并希望它们与 CLI 跨度出现在 **相同的分布式跟踪** 中。

SDK 可以在 JSON-RPC 有效负载上传播 W3C 跟踪上下文（`traceparent`/`tracestate`），以便应用程序范围和 CLI 跨度链接在一个分布式跟踪中。 例如，当你希望在应用中看到“处理工具调用”的 span 嵌套在 CLI 的“执行工具” span 内，或者将 SDK 调用显示为请求处理 span 的子 span 时，这会非常有用。

要沿跟踪进行成本归属，请订阅 `assistant.usage` 事件并检查 `apiEndpoint` (`AssistantUsageApiEndpoint`) 以查看轮次是否使用了 Chat Completions、Responses 或 Anthropic Messages；请参阅 [流式处理会话事件](/zh/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/streaming-events)。

#### SDK → CLI（出站）

对于 **Node.js**，请在 `onGetTraceContext` 客户端选项中提供回调函数。 仅当应用程序已使用 `@opentelemetry/api` 并且想要将范围与 CLI 的跨度链接时，才需要这样做。 SDK 在 `session.create`、`session.resume` 和 `session.send` RPC 前调用此回调：

<!-- docs-validate: skip -->

```typescript
import { CopilotClient } from "@github/copilot-sdk";
import { propagation, context } from "@opentelemetry/api";

const client = new CopilotClient({
  telemetry: { otlpEndpoint: "http://localhost:4318" },
  onGetTraceContext: () => {
    const carrier: Record<string, string> = {};
    propagation.inject(context.active(), carrier);
    return carrier; // { traceparent: "00-...", tracestate: "..." }
  },
});
```

对于 **Python**、**Go** 和 **.NET**，当配置相应的 OpenTelemetry/Activity API 时，跟踪上下文注入是自动的，无需回调。

#### CLI → SDK（传入）

当 CLI 调用工具处理程序时，CLI 的 span 中的 `traceparent` 和 `tracestate` 在所有语言中都可用：

* **Go**：`ToolInvocation.TraceContext` 字段是一个已恢复追踪的 `context.Context`，可直接将其用作你自定义跨度的父级。
* **Python**：通过 `trace_context()` 在处理程序周围自动回复跟踪上下文，子跨度会自动以 CLI 的跨度作为父级。
* **.NET**：通过 `RestoreTraceContext()` 动恢复追踪上下文，子 `Activity` 实例会自动以 CLI 的跨度作为父级。
* **Node.js**：由于 SDK 没有 OpenTelemetry 依赖，`traceparent` 和 `tracestate` 会作为原始字符串通过 `ToolInvocation` 对象传递。 如果需要，请手动还原上下文：

<!-- docs-validate: skip -->

```typescript
import { defineTool } from "@github/copilot-sdk";
import { propagation, context, trace } from "@opentelemetry/api";

const myTool = defineTool("my-tool", {
  description: "Do work",
  handler: async (args, invocation) => {
    // Restore the CLI's trace context as the active context
    const carrier = {
      traceparent: invocation.traceparent,
      tracestate: invocation.tracestate,
    };
    const parentCtx = propagation.extract(context.active(), carrier);

    // Create a child span under the CLI's span
    const tracer = trace.getTracer("my-app");
    return context.with(parentCtx, () =>
      tracer.startActiveSpan("my-tool", async (span) => {
        try {
          const result = await doWork(args);
          return result;
        } finally {
          span.end();
        }
      })
    );
  },
});

// Tool handlers are registered when the session is created.
const session = await client.createSession({ tools: [myTool] });
```

### 每种语言的依赖项

| 语言      | 依赖项                                  | 笔记                                                            |
| ------- | ------------------------------------ | ------------------------------------------------------------- |
| Node.js | —                                    | 无依赖项；为出站传播提供 `onGetTraceContext` 回调函数                         |
| Python  | `opentelemetry-api`                  | 利用 `pip install copilot-sdk[telemetry]` 进行安装                  |
| Go      | `go.opentelemetry.io/otel`           | 必需的依赖项                                                        |
| .NET    | —                                    | 使用内置 `System.Diagnostics.Activity`                            |
| Java    | `io.opentelemetry:opentelemetry-api` | 为基于 SDK 的设置添加此依赖项;配置 OpenTelemetry Java 代理或 SDK 时，跟踪上下文注入是自动的 |

## References

* [OpenTelemetry GenAI 语义约定](https://opentelemetry.io/docs/specs/semconv/gen-ai/)
* [OpenTelemetry MCP 语义约定](https://opentelemetry.io/docs/specs/semconv/gen-ai/mcp/)
* [OpenTelemetry Python SDK](https://opentelemetry.io/docs/instrumentation/python/)
* [Copilot SDK 文档](https://github.com/github/copilot-sdk)