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

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. 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:

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:

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:

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:

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:

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:

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, which contains implementation examples for all supported languages. Supplementary reusable content blocks for GitHub Enterprise Server appear in data/reusables/enterprise/opentelemetry-preview.md and data/reusables/enterprise/opentelemetry-migration.md, while feature gating is controlled via 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →