|
| 1 | +--- |
| 2 | +title: OpenTelemetry instrumentation for Copilot SDK |
| 3 | +shortTitle: OpenTelemetry |
| 4 | +intro: Learn how to add OpenTelemetry tracing to your {% data variables.copilot.copilot_sdk_short %} applications. |
| 5 | +product: '{% data reusables.gated-features.copilot-sdk %}' |
| 6 | +versions: |
| 7 | + feature: copilot |
| 8 | +contentType: how-tos |
| 9 | +category: |
| 10 | + - Author and optimize with Copilot |
| 11 | +--- |
| 12 | + |
| 13 | +> [!NOTE] |
| 14 | +> {% data variables.copilot.copilot_sdk_short %} is currently in {% data variables.release-phases.technical_preview %}. Functionality and availability are subject to change. |
| 15 | +
|
| 16 | +{% data variables.copilot.copilot_sdk %} has built-in support for configuring OpenTelemetry on the CLI process and propagating W3C Trace Context between the SDK and CLI. |
| 17 | + |
| 18 | +For examples in Python, Go, and .NET, see the `github/copilot-sdk` [repository](https://github.com/github/copilot-sdk/blob/main/docs/observability/opentelemetry.md). |
| 19 | + |
| 20 | +## Built-in telemetry support |
| 21 | + |
| 22 | +To opt in to telemetry, provide a `TelemetryConfig` when creating the client: |
| 23 | + |
| 24 | +```typescript copy |
| 25 | +import { CopilotClient } from "@github/copilot-sdk"; |
| 26 | + |
| 27 | +const client = new CopilotClient({ |
| 28 | + telemetry: { |
| 29 | + otlpEndpoint: "http://localhost:4318", |
| 30 | + }, |
| 31 | +}); |
| 32 | +``` |
| 33 | + |
| 34 | +### TelemetryConfig options |
| 35 | + |
| 36 | +| Option | Node.js | Description | |
| 37 | +|---|---|---| |
| 38 | +| OTLP endpoint | `otlpEndpoint` | OTLP HTTP endpoint URL | |
| 39 | +| File path | `filePath` | File path for JSON-lines trace output | |
| 40 | +| Exporter type | `exporterType` | `"otlp-http"` or `"file"` | |
| 41 | +| Source name | `sourceName` | Instrumentation scope name | |
| 42 | +| Capture content | `captureContent` | Whether to capture message content | |
| 43 | + |
| 44 | +## Trace context propagation |
| 45 | + |
| 46 | +> [!NOTE] |
| 47 | +> Most users don't need this. The `TelemetryConfig` above is all you need to collect traces from the CLI. Trace context propagation is an advanced feature for applications that create their own OpenTelemetry spans and want them to appear in the same distributed trace as the CLI's spans. |
| 48 | +
|
| 49 | +The SDK can propagate W3C Trace Context (`traceparent`/`tracestate`) on JSON-RPC payloads so that your application's spans and the CLI's spans are linked in one distributed trace. This is useful when, for example, you want to show the SDK call as a child of your request-handling span. |
| 50 | + |
| 51 | +For a detailed sequence diagram of the session flow, see the `github/copilot-sdk` [repository](https://github.com/github/copilot-sdk/blob/main/docs/observability/opentelemetry.md). |
| 52 | + |
| 53 | +### SDK to CLI (outbound) |
| 54 | + |
| 55 | +Provide an `onGetTraceContext` callback on the client options. This is only needed if your application already uses `@opentelemetry/api` and you want to link your spans with the CLI's spans. The SDK calls this callback before `session.create`, `session.resume`, and `session.send` RPCs: |
| 56 | + |
| 57 | +```typescript copy |
| 58 | +import { CopilotClient } from "@github/copilot-sdk"; |
| 59 | +import { propagation, context } from "@opentelemetry/api"; |
| 60 | + |
| 61 | +const client = new CopilotClient({ |
| 62 | + telemetry: { otlpEndpoint: "http://localhost:4318" }, |
| 63 | + onGetTraceContext: () => { |
| 64 | + const carrier: Record<string, string> = {}; |
| 65 | + propagation.inject(context.active(), carrier); |
| 66 | + return carrier; // { traceparent: "00-...", tracestate: "..." } |
| 67 | + }, |
| 68 | +}); |
| 69 | +``` |
| 70 | + |
| 71 | +### CLI to SDK (inbound) |
| 72 | + |
| 73 | +When the CLI invokes a tool handler, the `traceparent` and `tracestate` from the CLI's span are available. Since the SDK has no OpenTelemetry dependency, these are passed as raw strings on the `ToolInvocation` object. Restore the context manually if needed: |
| 74 | + |
| 75 | +```typescript copy |
| 76 | +import { propagation, context, trace } from "@opentelemetry/api"; |
| 77 | + |
| 78 | +session.registerTool(myTool, async (args, invocation) => { |
| 79 | + // Restore the CLI's trace context as the active context |
| 80 | + const carrier = { |
| 81 | + traceparent: invocation.traceparent, |
| 82 | + tracestate: invocation.tracestate, |
| 83 | + }; |
| 84 | + const parentCtx = propagation.extract(context.active(), carrier); |
| 85 | + |
| 86 | + // Create a child span under the CLI's span |
| 87 | + const tracer = trace.getTracer("my-app"); |
| 88 | + return context.with(parentCtx, () => |
| 89 | + tracer.startActiveSpan("my-tool", async (span) => { |
| 90 | + try { |
| 91 | + const result = await doWork(args); |
| 92 | + return result; |
| 93 | + } finally { |
| 94 | + span.end(); |
| 95 | + } |
| 96 | + }) |
| 97 | + ); |
| 98 | +}); |
| 99 | +``` |
| 100 | + |
| 101 | +## Further reading |
| 102 | + |
| 103 | +* [OpenTelemetry GenAI semantic conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/) in the OpenTelemetry documentation |
| 104 | +* [OpenTelemetry MCP semantic conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/mcp/) in the OpenTelemetry documentation |
| 105 | +* [OpenTelemetry Python SDK](https://opentelemetry.io/docs/instrumentation/python/) in the OpenTelemetry documentation |
0 commit comments