feat(telemetry): emit infra.provider on provision, up, and down#9091
feat(telemetry): emit infra.provider on provision, up, and down#9091hemarina wants to merge 6 commits into
Conversation
Record the resolved IaC provider (bicep/terraform/...) as a usage attribute in Manager.newProvider so it flows onto the provision/up/down command spans via the existing usage-attribute mechanism. Reuses the existing InfraProviderKey (no new field); updates the metrics-audit docs and telemetry_test comments accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds IaC provider telemetry to provisioning lifecycle commands.
Changes:
- Emits the resolved provider through usage attributes.
- Updates telemetry documentation and command classifications.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
manager.go |
Emits provider telemetry during initialization. |
telemetry_test.go |
Updates telemetry classification comments. |
feature-telemetry-matrix.md |
Documents emitting commands. |
telemetry-data.md |
Updates provisioning telemetry mapping. |
jongio
left a comment
There was a problem hiding this comment.
The provider resolves correctly, but a couple of things about where this attribute lands are worth deciding before merge.
Because it sits in the shared newProvider path, infra.provider now also lands on env refresh (cmd/env.go:1234) and pipeline config (cmd/pipeline.go:190) since both call provisionManager.Initialize. env refresh is classified as global-only in telemetry_test.go, and the docs this PR updates list the emitting commands as provision/up/down only, so the real emission scope is wider than the stated one.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jongio
left a comment
There was a problem hiding this comment.
One doc/impl consistency follow-up, inline on the provisioning telemetry row.
…and keep it off cmd.package span Emit infra.provider from the provision/up/down actions before provider work (instead of only after success), so failed and preview runs are segmentable by provider. Filter the key off up's synthetic cmd.package span, and add a unit test for that filter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jongio
left a comment
There was a problem hiding this comment.
Two low-severity items on the incremental changes, both inline on up_graph.go.
- The
usageAttributesExcludinghelper split thephaseDurationsdoc comment from its function. - Custom
workflows.upreturns before the graph run, socmd.upwill not carryinfra.provideron that path even though the updated docs list up as covered.
…providers, fix doc comment - up: record on upAction.Run before the custom-workflow branch and early init, so cmd.up carries the field on all paths (not just the unified graph). - privacy: emit built-in provider kinds raw, bucket any other (extension) provider to 'custom' so user-chosen names are never sent. - up_graph: remove now-duplicate emit; restore phaseDurations doc comment split by the helper. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jongio
left a comment
There was a problem hiding this comment.
One doc-accuracy point inline: the new raw name never emitted wording is broader than the code actually guarantees.
…st, scope docs, refresh field doc - Dedup resolved ProviderKind before bucketing so two different custom providers record 'mixed'. - Drop Test from the raw allowlist (buckets to 'custom') to match the documented enum. - Scope the 'raw name not emitted' guarantee to provision/up/down; note infra generate/synth emit the configured provider directly. - Refresh the InfraProviderKey doc comment in fields.go. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| func RecordInfraProviderUsage(layers []Options, defaultProvider DefaultProviderResolver) { | ||
| seen := map[ProviderKind]struct{}{} | ||
| for _, layer := range layers { | ||
| kind := layer.Provider | ||
| if kind == NotSpecified { | ||
| if defaultProvider == nil { | ||
| continue | ||
| } | ||
|
|
||
| resolved, err := defaultProvider() | ||
| if err != nil { | ||
| continue | ||
| } | ||
|
|
||
| kind = resolved | ||
| } | ||
|
|
||
| parsed, err := ParseProvider(kind) | ||
| if err != nil { | ||
| continue | ||
| } | ||
|
|
||
| seen[parsed] = struct{}{} | ||
| } |
| func infraProviderTelemetryValue(kind ProviderKind) string { | ||
| switch kind { | ||
| case Bicep, Terraform, Arm, Pulumi: | ||
| return string(kind) | ||
| default: | ||
| return InfraProviderCustom | ||
| } |
| | Pipeline provider | `pipeline.provider` | `pipeline config` | Distinguishes GitHub vs Azure DevOps | | ||
| | Pipeline auth | `pipeline.auth` | `pipeline config` | Distinguishes federated vs client-credentials | | ||
| | Infra provider | `infra.provider` | `infra generate`, `infra synth` | Distinguishes Bicep vs Terraform | | ||
| | Infra provider | `infra.provider` | `infra generate`, `infra synth`, `provision`, `up`, `down` | provision/up/down: resolved `bicep`/`terraform`/`arm`/`pulumi`, `custom` for extension providers (raw name not emitted), or `mixed` when layers differ. `infra generate`/`synth`: the configured `--provider` value emitted directly (`bicep`/`terraform`/`auto`, or a raw custom name) | |
jongio
left a comment
There was a problem hiding this comment.
Confirmed the incremental changes address my earlier telemetry-accuracy feedback. Deduping by resolved ProviderKind before bucketing now records mixed for two distinct custom providers (they previously collapsed to custom), and dropping Test from the raw allowlist keeps emitted values aligned with the documented enum. The provision/up/down vs generate/synth doc scoping reads accurately now.
Azure Dev CLI Install InstructionsInstall scriptsMacOS/Linux
bash: pwsh: WindowsPowerShell install MSI install Standalone Binary
MSI
Documentationlearn.microsoft.com documentationtitle: Azure Developer CLI reference
|
Fixes #9090
What
Emit the
infra.providertelemetry attribute so provisioning runs can be segmented by IaC provider.Previously it was only emitted by
azd infra generate/synth; this adds it to the provisioninglifecycle commands
provision,up, anddown.Design
A shared helper
provisioning.RecordInfraProviderUsage(layers, defaultProvider)computes a singledeterministic value from the command's configured layers:
bicep/terraform/arm/pulumi);custom— the raw name is never emitted (privacy);mixed(distinctProviderKinds are counted beforebucketing, so two different custom providers still record
mixed).It is invoked once per command, early (before provider work), from the lifecycle actions:
provision: top ofprovisionLayersGraph(covers preview + failure + success);up:upAction.Run, before the custom-workflow branch and early init (covers every up path);down: before the destroy loop.Emitting early keeps failed and preview runs segmentable by provider while staying scoped to
provision/up/down — it does not land on
env refresh/pipeline config.up's syntheticcmd.packagespan is filtered so the attribute stays oncmd.provision/cmd.uponly.infra generate/synthkeep their existing behavior (they emit the configured--providervalue directly, including
auto); thecustombucketing applies to the provision/up/down path.Telemetry governance
fields.InfraProviderKey(no new field;SystemMetadata/FeatureInsight);refreshed its source doc comment.
feature-telemetry-matrix.md,telemetry-schema.md, andtelemetry-data.mdfor the valuedomain and the provision/up/down vs generate/synth distinction.
commandsWithSpecificTelemetrycomments intelemetry_test.go.Tests
TestRecordInfraProviderUsage— single / default / uniform / mixed / custom-bucketed /two-custom→mixed / built-in+custom→mixed / empty / nil-resolver / failing-resolver.
TestUsageAttributesExcluding— thecmd.packagespan filter.Verification
go build ./...,gofmt -lclean.go test ./pkg/infra/provisioning/,./internal/cmd/,./cmd/(telemetry + up + down).