opentelemetry for github copilot

Copilot,
Traced.

Your AI pair programmer is a distributed system. It has been emitting OpenTelemetry this whole time.

about the last thing copilot did for you

Three questions, and I don’t
think anyone here can
answer them.

01

How many tokens?

Not roughly. The actual number your last turn sent to the model.

02

What did it cost?

In credits. For that one turn. On that one repo.

03

Was any of it cached?

Or did you pay full price to re-send a prompt the model had already seen?

the double standard

Your checkout service is better
instrumented than the thing
writing your code.

your checkout service

Fully observable

Traces. RED metrics. Structured logs. An on-call rotation. A dashboard someone actually looks at. Alerts that page a human at 3 a.m.

latency · error rate · saturation · cost per request
your ai coding agent

“Feels a bit slow today”

No traces, no baseline, no record of which model ran or what it spent. When it degrades you find out on Slack, from a colleague, in a shrug.

vibes · anecdotes · that one loud teammate
the twist This is not a missing-feature problem. The telemetry already exists — it ships in the product, it follows an open standard, and almost nobody has switched it on.
the reframe

There’s a distributed system
running on your laptop, and
you’ve been calling it autocomplete.

A planner that calls a model. A model that calls tools. Tools that call your file system, your shell, an MCP server two networks away. Retries, timeouts, a cache, and a bill. You have instrumented this exact shape a hundred times.

the entire integration

This is the whole thing.

No SDK to install. No agent to inject. No proxy. Copilot speaks OTLP natively — you just tell it where to send it.

VS Code · user settings.json
{
  "github.copilot.chat.otel.enabled": true,
  "github.copilot.chat.otel.exporterType": "otlp-http",
  "github.copilot.chat.otel.otlpEndpoint": "http://localhost:4318",
  "github.copilot.chat.otel.captureContent": false
}
Copilot CLI · same OTEL_* variables
setx COPILOT_OTEL_ENABLED        "true"
setx OTEL_EXPORTER_OTLP_ENDPOINT "http://localhost:4318"

# Leave OTEL_SERVICE_NAME unset. That single omission
# is what keeps VS Code and the CLI apart on the board.
why this is a big deal It is OTLP, and the attributes follow the OpenTelemetry GenAI semantic conventions. So it lands in Tempo, Jaeger, Application Insights, Grafana Cloud, Honeycomb, Datadog — whatever you already run. No new vendor.
before you promise anyone a dashboard

Which surfaces actually emit? Fewer than you’d hope.

Coverage map of Copilot surfaces that export OpenTelemetry as of July 2026.
what comes out of the wire

One turn is a trace you already know how to read.

A Copilot turn as a span tree: invoke_agent root with chat and execute_tool children, annotated with GenAI attributes.
demo 1

Click a span. live

the headline metric

Why one moved byte costs you 21,000 tokens.

Prompt cache anatomy: a stable prefix is read back; a single changed token near the front invalidates everything after it.
pick one number to care about

Cache hit rate is a leading indicator.

It is the closest thing Copilot has to a health metric — and it moves before anyone complains.

it means

Your prompt is stable

A high hit rate is a proxy for a well-behaved system prompt, a stable tool inventory, and sessions that aren’t thrashing their context window.

it predicts

Cost, before the invoice

Cached input bills at a fraction of fresh input. Hit rate falls today; the finance conversation happens next month.

it predicts

Latency, before the complaints

A hit shaves most of the time-to-first-token. "Copilot feels sluggish" is usually a hit-rate chart nobody was looking at.

the definitions, once cache_read.input_tokens > 0HIT · cache_creation.input_tokens > 0MISS · both zero → no cache in play.
where the telemetry goes

One wire, and four reasonable places to point it.

Architecture: VS Code and the Copilot CLI export OTLP to one of four backends — local Tempo, Azure with a local collector, an Azure Container Apps collector, or Grafana Cloud.
demo 2

Build your pipeline. Take the config. live

the gotcha that will bite you

service.name is not “where I was sitting”.

Surface versus agent grid: a CLI session started inside VS Code emits spans under two different service names.
fifteen minutes after you start

This is what falls out.

Grafana dashboard showing Copilot prompt-cache hits and misses, tokens, models and tool calls across both surfaces.
One dropdown at the top Copilot surface: All / VS Code / Copilot CLI. Every panel below re-queries.
Cache read tokens Prefix reused. Cheap, and roughly three times faster to first token.
Cache creation tokens Prefix rebuilt from scratch. This is the line you are trying to flatten.
Calls and p50 by model Which model actually served you, and how long it took — per surface.
Top tools, recent calls Every span links straight into the Tempo trace view. Click through to the raw attributes.
one board, one dropdown

The same questions, per surface.

Dashboard filtered to the VS Code surface: 17 LLM calls, 10 cache reads, 7 cache creations, 13 tool calls.
VS Code · service.name = copilot-chat
Dashboard filtered to the Copilot CLI surface: 13 LLM calls, 9 cache reads, 4 cache creations, 9 tool calls.
Copilot CLI · service.name = github-copilot
why this comparison is worth having Agent sessions and foreground chat have completely different shapes — turn length, tool-call volume, how fast they burn the context window. Averaged together, both look wrong.
demo 3

Four ways to destroy your hit rate. live

demo 4

Now multiply it by your team. live

field note

Cost is on the span now — you don’t have to infer it.

attributewhat it gives you
github.copilot.nano_aiuAI units × 10⁻⁹ — divide by 1e9 for the credits figure the CLI prints
github.copilot.costRequest cost as reported by the service
github.copilot.server_durationServer-side ms, versus the span’s wall clock
gen_ai.response.time_to_first_chunkTTFT in seconds, streaming
github.copilot.turn_countLLM round trips in the session
the docs say aiu · the wire says nano_aiu Verified against Copilot CLI 1.0.76: a run the CLI reported as “AI Credits 20.5” emitted nano_aiu = 20546625000.
the small win

Grafana unit si:nAIU — an SI nano prefix on a custom AIU unit — rescales 21758500000 to 21.8 AIU with no transformation at all.

the slide i would want someone to show me

Content capture off ≠ anonymous.

With content capture off, Copilot still ships a pseudonymous user id, tool and MCP inventory, skill names, custom agent names, and repository metadata.
from your laptop to everyone’s

The rollout path stopped being a hack.

Managed Copilot settings: three delivery channels feeding a telemetry policy block, and the precedence chain.
what to actually do

Monday morning, in order.

1

Twenty minutes: see your own data

docker compose up -d, paste four settings, use Copilot normally for an hour, open localhost:3001. Nothing leaves your laptop. No cloud account, no approval, no meeting.

2

One afternoon: find your worst prefix

Sort by cache_creation.input_tokens. Look for a repeating high value — that’s your volatile token. Overlay the session.* events to see whether it’s compaction or something you wrote.

3

Then, and only then, talk about a fleet

Put a collector in the path, drop enduser.pseudo.id, and roll it out with managed settings — with a baseline you can point at, and an answer ready for “are you watching me?”

the order matters Every failed observability rollout I’ve seen started at step 3. Earn the fleet with a number you already have.
bonus · things that cost me an evening

Six traps, pre-sprung.

trapwhat happens · what to do
Traces-only pipelineCopilot emits metrics and logs too. No metrics: pipeline in your collector and they’re silently dropped. Tempo can’t store metrics at all.
Protocol mismatchThe CLI defaults to http/json, VS Code to http/protobuf. Grafana Cloud’s gateway wants protobuf — set it explicitly.
OTEL_SERVICE_NAMESet it and both surfaces collapse into one name. Leave it alone.
Managed headersDelivered to the Chat extension exporter only, never the agent host — deliberately, to keep tokens out of subprocesses. An in-network collector side-steps it.
Workspace settingsUse User settings. A committed workspace setting points your teammates’ telemetry at your endpoint.
ReloadThe agent host reads config at start-up. Changed a setting and see nothing? Reload the window before you debug anything else.
one thing to take home

We let the tool that writes
our code be the one thing
we never measure.

It has been telling us the whole time — tokens, cost, latency, every cache miss and the reason for it. Four settings and a docker compose. Then it stops being a feeling and starts being a number.

everything is open source

Take it with you.

the repo

github.com/webmaxru/
copilot-opentelemetry

Docker Compose for the local stack, both collector configs, Azure provisioning scripts, and the two dashboards — TraceQL for Tempo, KQL for Azure Monitor. MIT licensed.

copilot-opentelemetry.isainative.dev
worth reading next
OTel GenAI semantic conventionsopentelemetry.io
Monitor agent usage with OpenTelemetryVS Code docs
Copilot CLI — OpenTelemetry monitoringdocs.github.com
Enterprise-managed OTel exportgithub.blog changelog
docker compose up -d 4 settings copilot-chat github-copilot

Questions — and I’d genuinely like to hear what your hit rate turns out to be.