Azure Developer CLI
August 12, 2026 · View on GitHub
How azd collects, exports, and transmits telemetry data.
Note
This is the public telemetry documentation. A Microsoft-internal companion set of docs (data pipeline, Kusto/Power BI reporting, runnable queries) is maintained separately for internal maintainers.
Overview
azd emits OpenTelemetry spans for every command execution. Telemetry flows through a local pipeline:
- Instrumentation — CLI, VS Code extension, and extensions emit OTel spans
- Export — Spans are converted to Application Insights envelopes and queued to disk
- Upload — A background process transmits envelopes to Application Insights
Microsoft-internal dashboards, data pipelines, and reporting infrastructure are documented separately for internal maintainers.
Data Flow
flowchart TB
subgraph Instrumentation ["Instrumentation"]
CLI["azd CLI<br/>(Go + OpenTelemetry)"]
VSC["VS Code Extension<br/>(@microsoft/vscode-azext-utils)"]
EXT["Extensions<br/>(structured error reporting)"]
end
subgraph Export ["CLI Export Pipeline"]
MW["Command Middleware<br/>cli/azd/cmd/middleware/telemetry.go"]
OTel["OTel TracerProvider"]
AIExp["App Insights Exporter<br/>SpanToEnvelope()"]
DiskQ["Disk Queue<br/>~/.azd/telemetry/*.trn"]
Upload["azd telemetry upload<br/>(background / deferred)"]
end
subgraph Ingestion ["Azure Monitor"]
AppInsights["Application Insights"]
end
CLI --> MW --> OTel --> AIExp --> DiskQ --> Upload --> AppInsights
VSC -->|VS Code telemetry framework| AppInsights
EXT -->|structured errors via host| MW
CLI Telemetry Pipeline (Detail)
1. Initialization
File: cli/azd/internal/telemetry/telemetry.go
When azd starts, the telemetry subsystem:
- Checks
AZURE_DEV_COLLECT_TELEMETRY— if set to"no", telemetry is disabled entirely - In Cloud Shell, shows a first-run consent notice (creates
~/.azd/first-runmarker) - Creates a
StorageQueuebacked by the filesystem at~/.azd/telemetry/ - Initializes the App Insights Exporter — a custom OTel
SpanExporterthat converts spans to Application Insights envelopes - Optionally adds:
- Stdout trace exporter (via
--trace-log-file) - OTLP HTTP exporter (via
--trace-log-url)
- Stdout trace exporter (via
- Creates an OTel
TracerProviderwith the configured exporters - Registers the provider globally via
otel.SetTracerProvider(tp)
2. Command Execution → Span Creation
File: cli/azd/cmd/middleware/telemetry.go
Every azd command is wrapped by the telemetry middleware:
user runs `azd deploy`
→ middleware.Run()
→ tracing.Start(ctx, "cmd.deploy") // creates OTel span
→ records attributes:
cmd.entry, cmd.flags, cmd.args.count,
platform.type, installed extensions (id@version)
→ runs the actual command action
→ on completion:
adds usage attributes (from baggage)
adds perf.interact_time
maps errors via cmd.MapError()
→ span.End()
For extension commands, the event name switches to ext.run and records ext.id, ext.version.
3. Span Export → Disk Queue
File: cli/azd/internal/telemetry/storage_exporter.go
The custom exporter:
- Receives completed OTel spans
- Converts each to an Application Insights
EnvelopewithRequestData(viaSpanToEnvelope()) - Serializes as NDJSON
- Enqueues to the disk queue (
~/.azd/telemetry/YYYYMMDDThhmmss_retry_random.trn) - Retries enqueue up to 3 times on failure
4. Disk Queue → Upload
Files: cli/azd/internal/telemetry/storage.go, uploader.go
The disk queue is a FIFO queue implemented as timestamped files:
Peek()picks the oldest ready item (not older thanitemFileMaxTimeKept)Cleanup()removes stale.tmpfiles and expired items
Upload happens via azd telemetry upload (triggered as a background subprocess):
- Acquires
upload.lock(file lock) - Loops:
Peek → Transmit → Remove - Retries up to
maxRetryCount=3with backoff - Handles partial success and
Retry-Afterheaders from App Insights ingestion
5. App Insights Envelope Format
File: cli/azd/internal/telemetry/appinsights-exporter/span_to_envelope.go
Each span becomes a contracts.Envelope containing RequestData:
| Envelope Field | Source |
|---|---|
IKey | Instrumentation key from connection string |
Tags[ai.application.ver] | service.version resource attribute |
Tags[ai.user.*] | UserAccountId, UserAuthUserId, UserId, SessionId |
Properties | String/bool span attributes |
Measurements | Int64/float64 span attributes |
Name | Span name (e.g., cmd.deploy) |
Duration | Span duration (App Insights format) |
ResponseCode | Span status / result code |
Success | Span status == OK |
Slice attributes are JSON-serialized into Properties.
VS Code Extension Telemetry
Files: ext/vscode/src/telemetry/
The VS Code extension uses a separate telemetry path from the CLI:
flowchart LR
VSExt["VS Code Extension"] --> VSFw["VS Code Telemetry Framework<br/>(@microsoft/vscode-azext-utils)"]
VSFw --> AppInsights["Application Insights"]
Key differences from CLI:
| Aspect | CLI | VS Code Extension |
|---|---|---|
| Framework | Go + OpenTelemetry | TypeScript + vscode-azext-utils |
| Export | Custom App Insights exporter + disk queue | VS Code telemetry framework (direct) |
| Opt-out | AZURE_DEV_COLLECT_TELEMETRY=no | telemetry.telemetryLevel=off in VS Code settings |
| Events | cmd.*, ext.*, mcp.*, etc. | azure-dev.* (activate, deactivate, tasks, surveys) |
Extension events (ext/vscode/src/telemetry/telemetryId.ts):
- Lifecycle:
azure-dev.activate,azure-dev.deactivate - CLI command tasks:
deploy,provision,up,down,init,login,restore,package - Environment/extension actions
- Survey tracking:
azure-dev.survey-check,azure-dev.survey-prompt-response - Activity statistics: tracks
totalActiveDaysvia VS Code Memento storage
Extension Framework Telemetry
File: cli/azd/cmd/middleware/telemetry.go (host side)
Extensions run as separate processes and report back to the azd host:
flowchart LR
Ext["Extension Process"] -->|structured error| Host["azd Host"]
Host -->|maps to span attributes| MW["Telemetry Middleware"]
MW --> Span["OTel Span<br/>(event: ext.run)"]
- Extension commands emit
ext.runevents withext.idandext.version - Extensions can report structured errors back to the host via
ExtensionService.ReportError - Error result codes follow conventions:
- Service errors:
ext.service.<service>.<statusCode> - Validation:
ext.validation.* - Auth:
ext.auth.* - Dependency:
ext.dependency.*
- Service errors:
- Extension lifecycle events:
ext.install,ext.update,ext.promote - Extensions published to the official registry can report usage events via
TelemetryService.ReportUsageafter going through a privacy review. Each event becomes anext.usagespan sharing the command's trace, carrying the extension's identity plus the caller's event name and attributes. Core namespaces every caller attribute underext.and bounds its size, but does not enumerate the values. Only extensions whose configured source matches the verified officialazdregistry name, type, and normalized URL are recorded — see ADR-001.
Consent & Privacy
Opt-Out
| Surface | Mechanism |
|---|---|
| CLI | Set AZURE_DEV_COLLECT_TELEMETRY=no |
| VS Code | Set telemetry.telemetryLevel to off in VS Code settings |
| Cloud Shell | First-run notice shown; opt-out instructions provided |
PII Protection
- Hashed fields:
project.template.id,project.template.version,project.name,env.nameare SHA-256 hashed (case-insensitive) before emission - Data classifications are annotated on every field:
PublicPersonalDataSystemMetadataCallstackOrExceptionCustomerContentEndUserPseudonymizedInformationOrganizationalIdentifiableInformation
- Privacy review required for: new telemetry fields, classification changes, any unhashed PII
Key Files
cli/azd/
├── cmd/middleware/telemetry.go # Command-level span middleware
├── internal/
│ ├── telemetry/
│ │ ├── telemetry.go # Pipeline init, env vars, consent
│ │ ├── storage.go # Disk queue (FIFO)
│ │ ├── storage_exporter.go # OTel exporter → disk queue
│ │ ├── uploader.go # Queue → App Insights upload
│ │ ├── notice.go # First-run consent notice
│ │ └── appinsights-exporter/
│ │ ├── span_to_envelope.go # Span → App Insights envelope
│ │ ├── transmitter.go # HTTP POST to ingestion
│ │ ├── endpoint_config.go # Connection string parsing
│ │ └── transmit_payload.go # NDJSON serialization
│ └── tracing/
│ ├── tracing.go # Global tracer
│ ├── attributes.go # Global/usage baggage
│ ├── events/events.go # All event name constants
│ └── fields/
│ ├── fields.go # All field keys + classifications
│ └── key.go # SHA-256 hashing helpers
ext/vscode/src/telemetry/
├── telemetryId.ts # Extension event IDs
└── activityStatisticsService.ts # Active days tracking
See Also
- Feature Telemetry Guide — How to add telemetry for new features
- Telemetry Data Reference — Schema, events, fields, query patterns
- Telemetry Overview — For product managers and leadership