# OpenTelemetry Instrumentation in GitHub Docs: Distributed Tracing for the Copilot SDK

> Discover how github/docs uses OpenTelemetry instrumentation for distributed tracing with the Copilot SDK. Learn about span export, OTLP HTTP, and W3C Trace-Context propagation.

- Repository: [GitHub/docs](https://github.com/github/docs)
- Tags: deep-dive
- Published: 2026-06-01

---

**The `github/docs` repository documents OpenTelemetry instrumentation through the Copilot SDK's `TelemetryConfig`, which exports spans to OTLP HTTP endpoints and propagates W3C Trace-Context across JSON-RPC boundaries between the CLI and user code.**

The `github/docs` repository maintains the official documentation for implementing **OpenTelemetry instrumentation** in GitHub Copilot-driven workflows. By supplying a `TelemetryConfig` when instantiating a `CopilotClient`, developers can enable end-to-end distributed tracing that correlates spans from the Copilot CLI with custom instrumentation in tool handlers across TypeScript, Python, Go, and other supported languages.

## Core Architecture of OpenTelemetry Instrumentation

The OpenTelemetry implementation centers on the `CopilotClient` configuration documented in [`content/copilot/how-tos/copilot-sdk/observability/opentelemetry.md`](https://github.com/github/docs/blob/main/content/copilot/how-tos/copilot-sdk/observability/opentelemetry.md). When telemetry is enabled, the SDK automatically initializes a tracer within the Copilot CLI process and configures an OTLP HTTP exporter.

### Telemetry Configuration

Provide an `otlpEndpoint` to the `telemetry` object when creating a client instance:

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

const client = new CopilotClient({
  telemetry: {
    otlpEndpoint: "http://localhost:4318",   // OTLP-HTTP collector
  },
});

```

This configuration triggers three automatic behaviors:
1. **Tracer initialization** inside the Copilot CLI process
2. **Span export** to the specified OTLP HTTP endpoint (or JSON-lines file)
3. **Context propagation** via W3C Trace-Context headers on every JSON-RPC call

### W3C Trace-Context Propagation

The SDK implements **W3C Trace-Context** (`traceparent`/`tracestate`) to maintain distributed trace continuity across process boundaries.

**Outbound propagation (SDK → CLI):** For languages with native OpenTelemetry support (Python, Go, .NET, Java), the SDK automatically injects the current context. In Node.js, you must provide an `onGetTraceContext` callback to supply the carrier manually:

```typescript
const client = new CopilotClient({
  telemetry: { otlpEndpoint: "http://localhost:4318" },
  onGetTraceContext: () => {
    const carrier: Record<string, string> = {};
    const { propagation, context } = require("@opentelemetry/api");
    propagation.inject(context.active(), carrier);
    return carrier; // contains traceparent & tracestate
  },
});

```

**Inbound propagation (CLI → SDK):** When the CLI invokes a tool handler, the trace context restores automatically for Python, Go, and .NET. For Node.js, the context arrives as raw strings in the `invocation` object and requires manual extraction:

```typescript
import { propagation, context, trace } from "@opentelemetry/api";

session.registerTool("myTool", async (args, invocation) => {
  // Re-inject the CLI's traceparent/tracestate
  const parentCtx = propagation.extract(
    context.active(),
    { traceparent: invocation.traceparent, tracestate: invocation.tracestate }
  );

  const tracer = trace.getTracer("my-app");
  return context.with(parentCtx, async () => {
    const span = tracer.startSpan("my-tool");
    try {
      return await doWork(args);
    } finally {
      span.end();
    }
  });
});

```

## Language-Specific Implementation Patterns

The `github/docs` source code details distinct dependencies and patterns for each runtime environment.

### Node.js: Callback-Based Context Injection

Node.js requires no additional OpenTelemetry packages within the SDK itself. You provide the `onGetTraceContext` callback if your application already uses `@opentelemetry/api`. This design keeps the base SDK lightweight while supporting custom instrumentation.

### Python: Automatic Context Management

Python implementations install the `opentelemetry-api` via `pip install copilot-sdk[telemetry]` and receive automatic context injection. Inside tool handlers, standard OpenTelemetry patterns create child spans:

```python
from copilot import CopilotClient

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

def my_tool(args):
    from opentelemetry import trace
    tracer = trace.get_tracer("my-app")
    with tracer.start_as_current_span("my-tool"):
        return do_work(args)

```

### Go: Native Context Propagation

Go implementations use `go.opentelemetry.io/otel` for automatic context injection. The `context.Context` parameter in tool handlers carries the trace information automatically:

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

session.RegisterTool("myTool", func(ctx context.Context, args MyArgs) (Result, error) {
    tracer := otel.Tracer("my-app")
    _, span := tracer.Start(ctx, "my-tool")
    defer span.End()
    return doWork(args)
})

```

### .NET, Java, and Rust

- **.NET**: Built-in `System.Diagnostics.Activity` provides automatic context injection without external dependencies
- **Java**: Requires `io.opentelemetry:opentelemetry-api` or the OpenTelemetry Java agent for automatic propagation
- **Rust**: Uses the same `TelemetryConfig` pattern with no extra crates required for basic export functionality

## Documentation Structure in the Repository

The `github/docs` repository organizes OpenTelemetry content across several key paths:

- **[`content/copilot/how-tos/copilot-sdk/observability/opentelemetry.md`](https://github.com/github/docs/blob/main/content/copilot/how-tos/copilot-sdk/observability/opentelemetry.md)** — Primary documentation containing `CopilotClient` initialization examples, per-language dependency tables, and trace-context propagation details
- **[`data/reusables/enterprise/opentelemetry-preview.md`](https://github.com/github/docs/blob/main/data/reusables/enterprise/opentelemetry-preview.md)** — Reusable content block indicating feature preview status for GitHub Enterprise Server (GHES)
- **[`data/reusables/enterprise/opentelemetry-migration.md`](https://github.com/github/docs/blob/main/data/reusables/enterprise/opentelemetry-migration.md)** — Reusable block describing migration paths from legacy monitoring to OpenTelemetry in GHES
- **[`data/features/ghes-opentelemetry.yml`](https://github.com/github/docs/blob/main/data/features/ghes-opentelemetry.yml)** — Feature flag definition controlling version-gated display of OpenTelemetry content for GHES instances

These files reference the Copilot SDK implementation while providing the structural framework for how users consume OpenTelemetry instrumentation documentation across GitHub's platform.

## Summary

- The **Copilot SDK** documented in `github/docs` enables OpenTelemetry instrumentation through a `TelemetryConfig` object supplied to `CopilotClient`
- **OTLP HTTP endpoints** receive spans automatically when configured, supporting collectors like Jaeger, Grafana Cloud, or the OpenTelemetry Collector
- **W3C Trace-Context** propagation ensures spans from user code appear as children of CLI spans, creating unified distributed traces
- **Language implementations vary**: Node.js requires manual `onGetTraceContext` callbacks, while Python, Go, and .NET offer automatic context injection
- **Documentation source files** reside in `content/copilot/how-tos/copilot-sdk/observability/` and `data/reusables/enterprise/`, with feature flags controlling GHES-specific content

## Frequently Asked Questions

### What OTLP endpoint format does the Copilot SDK expect?

The SDK expects an OTLP HTTP endpoint URL string, such as `http://localhost:4318`, passed to the `otlpEndpoint` property in the `TelemetryConfig` object. This endpoint receives span data in the OpenTelemetry Protocol format, compatible with standard collectors including the OpenTelemetry Collector, Jaeger, and Grafana Cloud.

### How does trace context propagation differ between Node.js and Python?

In **Python**, the Copilot SDK automatically handles W3C Trace-Context injection and extraction using the `opentelemetry-api`, requiring no manual context management in tool handlers. In **Node.js**, the SDK requires you to implement an `onGetTraceContext` callback to inject the current span context into a carrier for outbound calls, and you must manually extract `traceparent` and `tracestate` from the `invocation` object in tool handlers to create child spans.

### Where is the OpenTelemetry instrumentation documented in the github/docs repository?

The primary documentation lives in [`content/copilot/how-tos/copilot-sdk/observability/opentelemetry.md`](https://github.com/github/docs/blob/main/content/copilot/how-tos/copilot-sdk/observability/opentelemetry.md), which contains implementation examples for all supported languages. Supplementary reusable content blocks for GitHub Enterprise Server appear in [`data/reusables/enterprise/opentelemetry-preview.md`](https://github.com/github/docs/blob/main/data/reusables/enterprise/opentelemetry-preview.md) and [`data/reusables/enterprise/opentelemetry-migration.md`](https://github.com/github/docs/blob/main/data/reusables/enterprise/opentelemetry-migration.md), while feature gating is controlled via [`data/features/ghes-opentelemetry.yml`](https://github.com/github/docs/blob/main/data/features/ghes-opentelemetry.yml).

### Can traces from the Copilot SDK integrate with existing OpenTelemetry setups?

Yes. Because the SDK uses standard W3C Trace-Context propagation and OTLP HTTP export, spans emitted from the Copilot CLI and your tool handlers integrate seamlessly with existing OpenTelemetry collectors. Any custom spans you create using your language's OpenTelemetry API will appear as children of the CLI's root spans, provided you correctly extract and inject the trace context as shown in the Node.js, Python, and Go examples.