Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/docs/monitoring/agent_monitoring.md
13389 views

Monitoring Agent Usage with OpenTelemetry

Copilot Chat can export traces, metrics, and events via OpenTelemetry (OTel) — giving you real-time visibility into agent interactions, LLM calls, tool executions, and token usage.

All signal names and attributes follow the OTel GenAI Semantic Conventions, so the data works with any OTel-compatible backend: Jaeger, Grafana, Azure Monitor, Datadog, Honeycomb, and more.

Quick Start

The fastest way to see Copilot Chat traces locally — no cloud account required. This guide uses the Aspire Dashboard, a lightweight container image from Microsoft that provides a trace viewer with a built-in OTLP endpoint. It can be used standalone, without the rest of .NET Aspire.

Prerequisites

  • Docker installed

  • VS Code with the GitHub Copilot Chat extension

1. Start the Aspire Dashboard

docker run --rm -d \ -p 18888:18888 \ -p 4318:18890 \ --name aspire-dashboard \ mcr.microsoft.com/dotnet/aspire-dashboard:latest

This exposes the dashboard UI on port 18888 and an OTLP (HTTP) endpoint on port 4318.

2. Configure VS Code

Open Settings (Ctrl+,) and add:

{ "github.copilot.chat.otel.enabled": true, "github.copilot.chat.otel.captureContent": true }

Note: You can also use environment variables instead of VS Code settings (see Configuration). Environment variables always take precedence.

3. Generate Telemetry

Open Copilot Chat and send any message — for example, ask a question in Agent mode.

4. View Traces

Open http://localhost:18888Traces. You'll see invoke_agent spans with nested chat and execute_tool children.

Screenshot showing agent interaction traces in the Aspire Dashboard with spans for invoke_agent, chat, and execute_tool.

Teardown

docker stop aspire-dashboard

Tip: See the Aspire Dashboard standalone docs for more configuration options.


Configuration

VS Code Settings

Open Settings (Ctrl+,) and search for copilot otel:

SettingTypeDefaultDescription
github.copilot.chat.otel.enabledbooleanfalseEnable OTel emission
github.copilot.chat.otel.exporterTypestring"otlp-http"otlp-http, otlp-grpc, console, or file
github.copilot.chat.otel.otlpEndpointstring"http://localhost:4318"OTLP collector endpoint
github.copilot.chat.otel.captureContentbooleanfalseCapture full prompt/response content
github.copilot.chat.otel.outfilestring""File path for JSON-lines output
github.copilot.chat.otel.dbSpanExporter.enabledbooleanfalsePersist OTel spans to a local SQLite database for the Chat: Export Agent Traces DB command. Implicitly enables OTel.

Environment Variables

Environment variables always take precedence over VS Code settings.

VariableDefaultDescription
COPILOT_OTEL_ENABLEDfalseEnable OTel. Also enabled when OTEL_EXPORTER_OTLP_ENDPOINT is set.
COPILOT_OTEL_ENDPOINTOTLP endpoint URL (takes precedence over OTEL_EXPORTER_OTLP_ENDPOINT)
OTEL_EXPORTER_OTLP_ENDPOINTStandard OTel OTLP endpoint URL
OTEL_EXPORTER_OTLP_PROTOCOLhttp/protobufOTLP protocol. Only grpc changes behavior; all other values use HTTP.
COPILOT_OTEL_PROTOCOLOverride OTLP protocol (grpc or http). Falls back to OTEL_EXPORTER_OTLP_PROTOCOL.
OTEL_SERVICE_NAMEcopilot-chatService name in resource attributes
OTEL_RESOURCE_ATTRIBUTESExtra resource attributes (key1=val1,key2=val2)
COPILOT_OTEL_CAPTURE_CONTENTfalseCapture full prompt/response content
COPILOT_OTEL_LOG_LEVELinfoMin log level: trace, debug, info, warn, error
COPILOT_OTEL_FILE_EXPORTER_PATHWrite all signals to this file (JSON-lines)
COPILOT_OTEL_HTTP_INSTRUMENTATIONfalseEnable HTTP-level OTel instrumentation
OTEL_EXPORTER_OTLP_HEADERSAuth headers (e.g., Authorization=Bearer token)

Activation

OTel is off by default with zero overhead. It activates when:

  • COPILOT_OTEL_ENABLED=true, or

  • OTEL_EXPORTER_OTLP_ENDPOINT is set, or

  • github.copilot.chat.otel.enabled is true, or

  • github.copilot.chat.otel.dbSpanExporter.enabled is true (the SDK pipeline must be active to feed the SQLite store).

Commands

CommandDescription
Chat: Export Agent Traces DB (github.copilot.chat.otel.exportAgentTracesDB)Export the local SQLite span database to a .db file. Only available when github.copilot.chat.otel.dbSpanExporter.enabled is true.

What Gets Exported

Traces

Copilot Chat emits a hierarchical span tree for each agent interaction:

invoke_agent copilot [~15s] chat gpt-4o [~3s] (LLM requests tool calls) execute_tool readFile [~50ms] execute_tool runCommand [~2s] chat gpt-4o [~4s] (LLM generates final response) (span ends)

invoke_agent — wraps the entire agent orchestration (all LLM calls + tool executions).

AttributeRequirementExample
gen_ai.operation.nameRequiredinvoke_agent
gen_ai.provider.nameRequiredgithub
gen_ai.agent.nameRequiredcopilot
gen_ai.conversation.idRequireda1b2c3d4-...
gen_ai.request.modelRecommendedgpt-4o
gen_ai.response.modelRecommendedgpt-4o-2024-08-06
gen_ai.usage.input_tokensRecommended12500
gen_ai.usage.output_tokensRecommended3200
gen_ai.usage.cache_read.input_tokensWhen available8000
gen_ai.usage.cache_creation.input_tokensWhen available4200
copilot_chat.turn_countAlways4
error.typeOn errorError
gen_ai.input.messagesOpt-in (captureContent)[{"role":"user",...}]
gen_ai.output.messagesOpt-in (captureContent)[{"role":"assistant",...}]
gen_ai.tool.definitionsOpt-in (captureContent)[{"type":"function",...}]

chat — one span per LLM API call (span kind: CLIENT).

AttributeRequirementExample
gen_ai.operation.nameRequiredchat
gen_ai.provider.nameRequiredgithub
gen_ai.request.modelRequiredgpt-4o
gen_ai.conversation.idRequireda1b2c3d4-...
gen_ai.request.max_tokensAlways2048
gen_ai.request.temperatureWhen set0.1
gen_ai.request.top_pWhen set0.95
copilot_chat.request.max_prompt_tokensAlways128000
gen_ai.response.idOn responsechatcmpl-abc123
gen_ai.response.modelOn responsegpt-4o-2024-08-06
gen_ai.response.finish_reasonsOn response["stop"]
gen_ai.usage.input_tokensOn response1500
gen_ai.usage.output_tokensOn response250
gen_ai.usage.cache_read.input_tokensWhen available1200
gen_ai.usage.cache_creation.input_tokensWhen available300
copilot_chat.time_to_first_tokenOn response450
server.addressWhen availableapi.github.com
copilot_chat.debug_nameWhen availableagentMode
error.typeOn errorTimeoutError
gen_ai.input.messagesOpt-in (captureContent)[{"role":"system",...}]
gen_ai.system_instructionsOpt-in (captureContent)[{"type":"text",...}]

execute_tool — one span per tool invocation (span kind: INTERNAL).

AttributeRequirementExample
gen_ai.operation.nameRequiredexecute_tool
gen_ai.tool.nameRequiredreadFile
gen_ai.tool.typeRequiredfunction or extension (MCP tools)
gen_ai.tool.call.idRecommendedcall_abc123
gen_ai.tool.descriptionWhen availableRead the contents of a file
error.typeOn errorFileNotFoundError
gen_ai.tool.call.argumentsOpt-in (captureContent){"filePath":"/src/index.ts"}
gen_ai.tool.call.resultOpt-in (captureContent)(file contents or summary)

Metrics

GenAI Convention Metrics

MetricTypeUnitDescription
gen_ai.client.operation.durationHistogramsLLM API call duration
gen_ai.client.token.usageHistogramtokensToken counts (input/output)

gen_ai.client.operation.duration attributes:

AttributeDescription
gen_ai.operation.nameOperation type (e.g., chat)
gen_ai.provider.nameProvider (e.g., github, anthropic)
gen_ai.request.modelRequested model
gen_ai.response.modelResolved model (if different)
server.addressServer hostname
server.portServer port
error.typeError class (if failed)

gen_ai.client.token.usage attributes:

AttributeDescription
gen_ai.operation.nameOperation type
gen_ai.provider.nameProvider name
gen_ai.token.typeinput or output
gen_ai.request.modelRequested model
gen_ai.response.modelResolved model
server.addressServer hostname

Extension-Specific Metrics

MetricTypeUnitDescription
copilot_chat.tool.call.countCountercallsTool invocations by name and success
copilot_chat.tool.call.durationHistogrammsTool execution latency
copilot_chat.agent.invocation.durationHistogramsAgent mode end-to-end duration
copilot_chat.agent.turn.countHistogramturnsLLM round-trips per agent invocation
copilot_chat.session.countCountersessionsChat sessions started
copilot_chat.time_to_first_tokenHistogramsTime to first SSE token

copilot_chat.tool.call.count attributes: gen_ai.tool.name, success (boolean)

copilot_chat.tool.call.duration attributes: gen_ai.tool.name

copilot_chat.agent.invocation.duration attributes: gen_ai.agent.name

copilot_chat.agent.turn.count attributes: gen_ai.agent.name

copilot_chat.time_to_first_token attributes: gen_ai.request.model

Agent Activity & Outcome Metrics

These metrics track the activity and outcomes of agentic code changes across all surfaces (agent mode, inline chat, background CLI, cloud sessions).

MetricTypeUnitDescription
copilot_chat.edit.acceptance.countCountereditsEdit accept/reject decisions (inline chat, chat editing, hunk-level)
copilot_chat.chat_edit.outcome.countCountereditsFile-level chat editing session outcomes (accepted/rejected/saved)
copilot_chat.lines_of_code.countCounterlinesLines of code added/removed by accepted agent edits
copilot_chat.edit.survival.four_gramHistogramratio (0-1)4-gram text similarity survival score
copilot_chat.edit.survival.no_revertHistogramratio (0-1)No-revert survival score
copilot_chat.user.action.countCounteractionsUser engagement: copy, insert, apply, followup
copilot_chat.user.feedback.countCountervotesThumbs up/down on chat responses
copilot_chat.agent.edit_response.countCounterresponsesAgent edit responses by success/error
copilot_chat.agent.summarization.countCountereventsContext summarization outcomes (applied/failed)
copilot_chat.pull_request.countCounterPRsPull requests created via CLI agent
copilot_chat.cloud.session.countCountersessionsCloud/remote agent sessions by partner
copilot_chat.cloud.pr_ready.countCountereventsRemote agent job PR ready notifications

copilot_chat.edit.acceptance.count attributes: copilot_chat.edit.source (inline_chat/chat_editing/chat_editing_hunk/apply_patch/replace_string/code_mapper), copilot_chat.edit.outcome (accepted/rejected), copilot_chat.language_id (optional)

copilot_chat.chat_edit.outcome.count attributes: copilot_chat.edit.source, copilot_chat.edit.outcome (accepted/rejected/saved), copilot_chat.language_id (optional), copilot_chat.has_remaining_edits (optional)

copilot_chat.lines_of_code.count attributes: type (added/removed), copilot_chat.language_id (optional)

copilot_chat.edit.survival.four_gram attributes: copilot_chat.edit.source, copilot_chat.time_delay_ms

copilot_chat.edit.survival.no_revert attributes: copilot_chat.edit.source, copilot_chat.time_delay_ms

copilot_chat.user.action.count attributes: action (copy/insert/apply/followup)

copilot_chat.user.feedback.count attributes: rating (positive/negative)

copilot_chat.agent.edit_response.count attributes: outcome (success/error)

copilot_chat.agent.summarization.count attributes: outcome (applied/failed)

copilot_chat.cloud.session.count attributes: partner_agent (copilot/claude/codex)

Events

gen_ai.client.inference.operation.details

Emitted after each LLM API call with full inference metadata.

AttributeDescription
gen_ai.operation.nameAlways chat
gen_ai.request.modelRequested model
gen_ai.response.modelResolved model
gen_ai.response.idResponse ID
gen_ai.response.finish_reasonsStop reasons (e.g., ["stop"])
gen_ai.usage.input_tokensInput token count
gen_ai.usage.output_tokensOutput token count
gen_ai.request.temperatureTemperature (if set)
gen_ai.request.max_tokensMax tokens (if set)
error.typeError class (if failed)
gen_ai.input.messagesFull prompt messages (captureContent only)
gen_ai.system_instructionsSystem prompt (captureContent only)
gen_ai.tool.definitionsTool schemas (captureContent only)

copilot_chat.session.start

Emitted when a new chat session begins (top-level agent invocations only, not subagents).

AttributeDescription
session.idSession identifier
gen_ai.request.modelInitial model
gen_ai.agent.nameChat participant name

copilot_chat.tool.call

Emitted when a tool invocation completes.

AttributeDescription
gen_ai.tool.nameTool name
duration_msExecution time in milliseconds
successtrue or false
error.typeError class (if failed)

copilot_chat.agent.turn

Emitted for each LLM round-trip within an agent invocation.

AttributeDescription
turn.indexTurn number (0-indexed)
gen_ai.usage.input_tokensInput tokens this turn
gen_ai.usage.output_tokensOutput tokens this turn
tool_call_countNumber of tool calls this turn

Agent Activity & Outcome Events

These events provide drill-down detail for the agent activity metrics above. They are emitted as OTel log records.

copilot_chat.edit.feedback

Emitted when a user accepts or rejects a file-level edit from the agent.

AttributeDescription
outcomeaccepted or rejected
language_idLanguage of the edited file
participantChat participant that proposed the edit
request_idChat request identifier
edit_surfaceagent or inline_chat
has_remaining_editsWhether unreviewed edits remain
is_notebookWhether the file is a notebook
copilot_chat.edit.hunk.action

Emitted when a user accepts or rejects an individual hunk.

AttributeDescription
outcomeaccepted or rejected
language_idLanguage of the edited file
request_idChat request identifier
line_countTotal lines in the hunk
lines_addedLines added
lines_removedLines removed
copilot_chat.inline.done

Emitted when an inline chat edit is accepted or rejected.

AttributeDescription
acceptedtrue or false
language_idLanguage of the edited file
edit_countNumber of edits suggested
edit_line_countTotal lines across all edits
reply_typeHow the response was shown
is_notebookWhether the document is a notebook
copilot_chat.edit.survival

Emitted at intervals (5s, 30s, 2min, 5min, 10min, 15min) after an edit is accepted, measuring how much of the AI-generated code survives.

AttributeDescription
edit_sourceapply_patch, replace_string, code_mapper, or inline_chat
survival_rate_four_gram0-1 ratio of AI edit still present (4-gram similarity)
survival_rate_no_revert0-1 ratio of edit ranges not reverted
time_delay_msMilliseconds since edit acceptance
did_branch_changeWhether git branch changed (ignore if true)
request_idChat request identifier
copilot_chat.user.feedback

Emitted when a user votes on a chat response (thumbs up/down).

AttributeDescription
ratingpositive or negative
participantChat participant name
conversation_idConversation session ID
request_idChat request identifier
copilot_chat.cloud.session.invoke

Emitted when a cloud/remote agent session is started.

AttributeDescription
partner_agentcopilot, claude, or codex
modelModel identifier
request_idChat request identifier

Resource Attributes

All signals carry:

AttributeValue
service.namecopilot-chat (configurable via OTEL_SERVICE_NAME)
service.versionExtension version
session.idUnique per VS Code window

Add custom resource attributes with OTEL_RESOURCE_ATTRIBUTES:

export OTEL_RESOURCE_ATTRIBUTES="team.id=platform,department=engineering"

These custom attributes are included in all traces, metrics, and events, allowing you to:

  • Filter metrics by team or department

  • Create team-specific dashboards and alerts

  • Track usage across organizational boundaries

Note: OTEL_RESOURCE_ATTRIBUTES uses comma-separated key=value pairs. Values cannot contain spaces, commas, or semicolons. Use percent-encoding for special characters (e.g., org.name=John%27s%20Org).


Content Capture

By default, no prompt content, responses, or tool arguments are captured — only metadata like model names, token counts, and durations.

To capture full content, add to your VS Code settings:

{ "github.copilot.chat.otel.captureContent": true }

This populates these span attributes:

AttributeContent
gen_ai.input.messagesFull prompt messages (JSON)
gen_ai.output.messagesFull response messages (JSON)
gen_ai.system_instructionsSystem prompt
gen_ai.tool.definitionsTool schemas
gen_ai.tool.call.argumentsTool input arguments
gen_ai.tool.call.resultTool output

Content is captured in full with no truncation.

Warning: Content capture may include sensitive information such as code, file contents, and user prompts. Only enable in trusted environments.


Example Configurations

OTLP/gRPC:

{ "github.copilot.chat.otel.enabled": true, "github.copilot.chat.otel.exporterType": "otlp-grpc", "github.copilot.chat.otel.otlpEndpoint": "http://localhost:4317" }

Remote collector with authentication:

{ "github.copilot.chat.otel.enabled": true, "github.copilot.chat.otel.otlpEndpoint": "https://collector.example.com:4318" }

Note: Authentication headers are only configurable via the OTEL_EXPORTER_OTLP_HEADERS environment variable (e.g., Authorization=Bearer your-token). See Environment Variables.

File-based output (offline / CI):

{ "github.copilot.chat.otel.enabled": true, "github.copilot.chat.otel.exporterType": "file", "github.copilot.chat.otel.outfile": "/tmp/copilot-otel.jsonl" }

Console output (quick debugging):

{ "github.copilot.chat.otel.enabled": true, "github.copilot.chat.otel.exporterType": "console" }

Subagent Trace Propagation

When an agent invokes a subagent (e.g., via the runSubagent tool), Copilot Chat automatically propagates the trace context so the subagent's invoke_agent span is parented to the calling agent's execute_tool span. This produces a connected trace tree:

invoke_agent copilot [~30s] chat gpt-4o [~3s] execute_tool runSubagent [~20s] invoke_agent Explore [~18s] child via trace context chat gpt-4o [~2s] execute_tool searchFiles [~200ms] execute_tool readFile [~50ms] chat gpt-4o [~3s] chat gpt-4o [~4s] (span ends)

This propagation works across async boundaries — the parent's trace context is stored when runSubagent starts and retrieved when the subagent begins its invoke_agent span.


Background Agents (Copilot CLI)

When OTel is enabled, all agent types are automatically instrumented — no additional configuration needed. The same settings that enable foreground agent traces also enable Copilot CLI traces.

Copilot CLI (Background Agent)

The Copilot CLI SDK runs in the same VS Code process and produces a rich trace hierarchy including subagents, permissions, hooks, and tool calls:

copilot-chat invoke_agent copilotcli [~45s] extension wrapper github-copilot invoke_agent [~42s] SDK native spans chat claude-sonnet-4.6 [~16s] hook postToolUse hook execution hook postToolUse execute_tool task [~18s] invoke_agent task subagent chat claude-sonnet-4.6 execute_tool bash permission execute_tool report_intent chat claude-sonnet-4.6 [~4s] hook sessionEnd session lifecycle hook

The extension wrapper span (invoke_agent copilotcli, service copilot-chat) parents the SDK's native spans (service github-copilot). Both appear in the same trace in your collector.

Agent Debug Log panel: CLI sessions show the full SDK hierarchy in the Tree View — identical to what appears in Grafana/Jaeger. This works even when OTel export is disabled, because the SDK's internal tracing is always active for the debug panel.

Content in the debug panel: When OTel export is disabled (the default), the debug panel automatically captures full prompt/response content. When OTel export is enabled, content capture is controlled by the captureContent setting — the same flag applies to both the debug panel and OTLP export. To see content in the debug panel while OTel is enabled, set github.copilot.chat.otel.captureContent to true.

Copilot CLI (Terminal Session)

Terminal CLI sessions ("New Copilot CLI Session") run as a separate process. When OTel is enabled, the extension forwards COPILOT_OTEL_ENABLED and OTEL_EXPORTER_OTLP_ENDPOINT to the terminal process. Terminal traces appear as independent root traces (service github-copilot) — they are not linked to extension traces.

Note: The CLI runtime only supports otlp-http. When otlp-grpc is configured, the terminal CLI still uses HTTP. Backends that serve both protocols on the same port (e.g., Aspire Dashboard) work transparently.

Filtering by Agent Type

In your trace viewer, filter by service.name to see traces from specific agents:

service.nameSource
copilot-chatForeground agent, CLI wrapper, and Claude agent spans (extension-emitted)
github-copilotCLI SDK native spans + CLI terminal
claude-codeClaude Code subprocess SDK telemetry (when CLAUDE_CODE_ENABLE_TELEMETRY is forwarded)

Within the copilot-chat service, distinguish agent types by gen_ai.agent.name:

gen_ai.agent.nameAgent Type
GitHub Copilot ChatForeground agent (agent mode)
copilotcliCLI wrapper span
claudeClaude agent

Claude Agent

When OTel is enabled, Claude agent sessions produce extension-level spans (service copilot-chat) following GenAI semantic conventions.

The extension creates spans by intercepting Claude SDK messages and proxying LLM calls through a local HTTP server to CAPI:

copilot-chat invoke_agent claude [~33s] chat claude-haiku-4.5 [~5s] (LLM call via CAPI proxy) execute_tool Agent [~11s] (subagent invocation) chat claude-haiku-4.5 [~4s] (subagent LLM call) execute_tool Grep [~20ms] (subagent tool) chat claude-haiku-4.5 [~7s] (subagent LLM call) chat claude-haiku-4.5 [~3s] execute_tool Write [~40ms] chat claude-haiku-4.5 [~3s] execute_hook Stop [~10ms] (hook execution)

invoke_agent claude — root span per user request.

AttributeExample
gen_ai.operation.nameinvoke_agent
gen_ai.agent.nameclaude
gen_ai.provider.namegithub
gen_ai.request.modelclaude-haiku-4.5
gen_ai.response.modelclaude-haiku-4-5
gen_ai.usage.input_tokens103739 (parent-only, excludes subagent tokens)
gen_ai.usage.output_tokens1100
gen_ai.usage.cache_read.input_tokens64062
gen_ai.usage.cache_creation.input_tokens39629
copilot_chat.turn_count8
copilot_chat.total_cost_usd0.067 (session-wide, includes subagents)
copilot_chat.chat_session_idVS Code session ID

chat — one span per LLM API call, created by chatMLFetcher via the Claude language model proxy server. Same attributes as foreground agent chat spans (token usage, TTFT, response model, cache breakdown).

execute_tool — one span per tool invocation. When the tool is Agent (subagent), child chat and execute_tool spans are nested underneath, giving full subagent visibility.

execute_hook — one span per Claude hook execution (e.g., Stop hooks).


Interpreting the Data

Traces — Visualize the full agent execution in Jaeger or Grafana Tempo. Each invoke_agent span contains child chat and execute_tool spans, making it easy to identify bottlenecks and debug failures. Subagent invocations appear as nested invoke_agent spans under execute_tool runSubagent (foreground agent) or under execute_tool Agent (Claude agent).

Metrics — Track token usage trends by model and provider, monitor tool success rates via copilot_chat.tool.call.count, and watch perceived latency with copilot_chat.time_to_first_token. Agent activity metrics (copilot_chat.edit.acceptance.count, copilot_chat.edit.survival.four_gram, copilot_chat.lines_of_code.count) power accept rate and edit survival dashboards. All metrics carry the same resource attributes (service.name, service.version, session.id) for consistent filtering.

Eventscopilot_chat.session.start tracks session creation. copilot_chat.tool.call events provide per-invocation timing and error details. copilot_chat.edit.feedback and copilot_chat.edit.survival events enable drill-down into which edits were accepted/rejected and how code survival varies by edit source. copilot_chat.user.feedback links thumbs-up/down votes to specific conversations for quality investigation. gen_ai.client.inference.operation.details gives the full LLM call record including token usage and, when content capture is enabled, the complete prompt/response messages. Use gen_ai.conversation.id to correlate all signals belonging to the same session.


Initialization & Buffering

The OTel SDK is loaded asynchronously via dynamic imports to avoid blocking extension startup. Events emitted before initialization completes are buffered (up to 1,000 items) and replayed once the SDK is ready. If initialization fails, buffered events are discarded and all subsequent calls become no-ops — the extension continues to function normally.

First successful span export is logged to the console ([OTel] First span batch exported successfully via ...) to confirm end-to-end connectivity.


Backend Setup Guides

Copilot Chat's OTel data works with any OTLP-compatible backend. This section provides step-by-step setup guides for recommended backends.

Aspire Dashboard

See Quick Start above for setup. The Aspire Dashboard is the simplest option — a single Docker container with a built-in OTLP endpoint and trace viewer. No cloud account or collector needed.

OTel Collector + Azure Application Insights

Azure Application Insights ingests OTel traces, metrics, and logs through an OTel Collector with the azuremonitor exporter. This repo includes a ready-to-use collector setup in docs/monitoring/.

1. Create an Application Insights resource:

  1. Go to the Azure Portal.

  2. Click Create a resource → search Application InsightsCreate.

  3. Choose your subscription, resource group, name, and region → Review + CreateCreate.

  4. Once deployed, go to the resource → Overview → copy the Connection String.

2. Start the OTel Collector:

export APPLICATIONINSIGHTS_CONNECTION_STRING="InstrumentationKey=...;IngestionEndpoint=..." cd docs/monitoring docker compose up -d

Verify the collector is healthy:

# Should return 200 curl -s -o /dev/null -w "%{http_code}" http://localhost:4328/v1/traces \ -X POST -H "Content-Type: application/json" -d '{"resourceSpans":[]}'

3. Configure VS Code:

Open Settings (Ctrl+,) and add:

{ "github.copilot.chat.otel.enabled": true, "github.copilot.chat.otel.exporterType": "otlp-http", "github.copilot.chat.otel.otlpEndpoint": "http://localhost:4328" }

Optionally, to capture full prompt/response content:

{ "github.copilot.chat.otel.captureContent": true }

Warning: Content capture includes prompts, code, and file contents. Only enable in trusted environments.

4. Generate telemetry — Open Copilot Chat and send any message (e.g., use Agent mode).

5. Verify data:

  • Jaeger (local): Open http://localhost:16687, select service copilot-chat, click Find Traces.

  • App Insights (Azure): Go to your Application Insights resource → Transaction search → filter by "Trace" or "Request".

Run this query in Application Insights → Logs to confirm:

traces | where timestamp > ago(1h) | where message contains "GenAI" or message contains "copilot_chat" | project timestamp, message, customDimensions | order by timestamp desc

For metrics (may take 5–10 minutes to appear):

customMetrics | where timestamp > ago(1h) | where name startswith "gen_ai" or name startswith "copilot_chat" | summarize avg(value), count() by name

Collector config (docs/monitoring/otel-collector-config.yaml):

receivers: otlp: protocols: http: endpoint: 0.0.0.0:4318 grpc: endpoint: 0.0.0.0:4317 exporters: azuremonitor: connection_string: "${APPLICATIONINSIGHTS_CONNECTION_STRING}" debug: verbosity: basic service: pipelines: traces: receivers: [otlp] exporters: [azuremonitor, debug] metrics: receivers: [otlp] exporters: [azuremonitor, debug]

Note: The docker-compose maps ports to 4328/4327 on the host to avoid conflicts. Adjust in docker-compose.yaml if needed. Add additional exporters (e.g., otlphttp/jaeger) to fan out to multiple backends. See docs/monitoring/otel-collector-config.yaml for the full config including batch processor and logs pipeline.

Jaeger

Jaeger is an open-source distributed tracing platform. It accepts OTLP directly — no collector needed.

1. Start Jaeger:

docker run -d --name jaeger -p 16686:16686 -p 4318:4318 jaegertracing/jaeger:latest

2. Configure VS Code:

{ "github.copilot.chat.otel.enabled": true, "github.copilot.chat.otel.otlpEndpoint": "http://localhost:4318" }

3. Verify: Open http://localhost:16686, select service copilot-chat, and click Find Traces.

Langfuse

Langfuse is an open-source LLM observability platform with native OTLP ingestion and support for OTel GenAI Semantic Conventions. See the Langfuse docs for full details on capabilities and limitations.

Setup:

{ "github.copilot.chat.otel.enabled": true, "github.copilot.chat.otel.otlpEndpoint": "http://localhost:3000/api/public/otel", "github.copilot.chat.otel.captureContent": true }

Then set the auth header via environment variable (required — no VS Code setting for headers):

export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic $(echo -n '<public-key>:<secret-key>' | base64)"

Replace <public-key> and <secret-key> with your Langfuse API keys from Settings → API Keys.

Verify: Open Langfuse → Traces. You should see invoke_agent traces with nested chat and execute_tool spans.

Other Backends

Any OTLP-compatible backend works with Copilot Chat's OTel output. Some options:

BackendDescription
JaegerOpen-source distributed tracing platform
Grafana Tempo + PrometheusOpen-source traces + metrics stack

Refer to each backend's documentation for OTLP ingestion setup.


Security & Privacy

  • Off by default. No OTel data is emitted unless explicitly enabled. When disabled, the OTel SDK is not loaded at all — zero runtime overhead.

  • No content by default. Prompts, responses, and tool arguments require opt-in via captureContent.

  • No PII in default attributes. Session IDs, model names, and token counts are not personally identifiable.

  • User-configured endpoints. Data goes only where you point it — no phone-home behavior.

  • Dynamic imports only. OTel SDK packages are loaded on-demand, ensuring zero bundle impact when disabled.