Appearance
Copilot SDK 内置 OpenTelemetry 支持,通过 telemetry.otlpEndpoint 配置即可将 trace 数据发送到任何 OTLP 兼容的后端(Jaeger、Zipkin、OTEL Collector 等)。通过 onGetTraceContext 和 W3C Trace Context 传播,可以把 SDK、CLI 进程和自定义工具的 span 串联成完整的分布式追踪链。
GitHub Copilot SDK OpenTelemetry 可观测性:分布式追踪配置
基本配置
OpenTelemetry 追踪默认关闭,需要显式配置:
typescript
import { CopilotClient } from '@github/copilot-sdk'
const client = new CopilotClient({
telemetry: {
otlpEndpoint: 'http://localhost:4318' // OTLP HTTP 端点
}
})Telemetry 配置选项
| 选项 | 类型 | 说明 |
|---|---|---|
otlpEndpoint | string | OTLP HTTP 端点 URL |
filePath | string | JSON Lines 格式的 trace 文件路径 |
exporterType | string | "otlp-http" 或 "file" |
sourceName | string | 插桩作用域名称(instrumentation scope) |
captureContent | boolean | 是否在 trace 中记录消息内容 |
导出到文件(本地调试)
typescript
const client = new CopilotClient({
telemetry: {
exporterType: 'file',
filePath: '/tmp/copilot-traces.jsonl'
}
})跨进程 Trace Context 传播
SDK 运行在 Node.js 进程中,而 CLI 是独立的子进程。要把两边的 trace 串联起来,使用 onGetTraceContext 把 W3C Trace Context 注入到 CLI 请求中:
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)
// 返回 W3C 格式的 headers: { traceparent: "00-...", tracestate: "..." }
return carrier
}
})在自定义工具中还原 Trace Context
当 CLI 调用你的自定义工具时,invocation 参数中包含 traceparent 和 tracestate,可以用来还原 trace 上下文,让工具的 span 成为同一条 trace 的子节点:
typescript
import { propagation, context, trace } from '@opentelemetry/api'
session.registerTool(myTool, async (args, invocation) => {
// 从 invocation 中提取 trace context
const carrier = {
traceparent: invocation.traceparent,
tracestate: invocation.tracestate
}
// 还原父 span 的 context
const parentCtx = propagation.extract(context.active(), carrier)
const tracer = trace.getTracer('my-app')
return context.with(parentCtx, () =>
tracer.startActiveSpan('my-tool', async (span) => {
try {
const result = await doWork(args)
span.setAttribute('result.size', result.length)
return result
} catch (error) {
span.recordException(error as Error)
throw error
} finally {
span.end()
}
})
)
})这样,整条请求链路(用户请求 → SDK → CLI → 工具调用)都会出现在同一个 trace 中,方便在 Jaeger/Zipkin/Tempo 中追踪完整路径。
配合 OTEL Collector
生产环境推荐部署 OpenTelemetry Collector 作为 trace 聚合点:
yaml
# otel-collector.yaml
receivers:
otlp:
protocols:
http:
endpoint: 0.0.0.0:4318
exporters:
jaeger:
endpoint: jaeger:14250
# 或者发到 Prometheus + Tempo
otlp/tempo:
endpoint: tempo:4317
service:
pipelines:
traces:
receivers: [otlp]
exporters: [jaeger]SDK 配置指向 Collector:
typescript
const client = new CopilotClient({
telemetry: { otlpEndpoint: 'http://otel-collector:4318' }
})隐私注意事项
captureContent: true 会把对话内容记录到 trace 中,方便调试但可能包含敏感信息。生产环境建议默认关闭,仅在开发调试时开启:
typescript
const client = new CopilotClient({
telemetry: {
otlpEndpoint: process.env.OTLP_ENDPOINT!,
captureContent: process.env.NODE_ENV === 'development'
}
})常见问题
Q: 用 Jaeger All-in-One 本地调试怎么配置?
A: 运行 docker run -p 4318:4318 -p 16686:16686 jaegertracing/all-in-one,然后 otlpEndpoint: "http://localhost:4318",在 http://localhost:16686 查看 trace。
Q: SDK 默认会发送哪些 span?
A: 主要包括:createSession、sendPrompt、tool.call(每次工具调用)、CLI 通信的 JSON-RPC span。具体遵循 OpenTelemetry GenAI 语义约定。
Q: 不想用 OTLP,可以直接打印到控制台吗?
A: 用 exporterType: "file" 导出到文件,然后用 tail -f 监控。或者在 OTEL SDK 中注册 ConsoleSpanExporter 打印到 stdout——这是 OpenTelemetry 标准用法,SDK 层面不特殊处理。