feat(telemetry): emit infra.provider on provision, up, and down#9091
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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.
…na/issue-9090-infra-provider-telemetry
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
cli/azd/cmd/down.go:190
- [azd-code-reviewer] This help text promises that a non-interactive Terraform project exits without deleting anything, but the loop intentionally continues after a Terraform layer is previewed and can delete layers using other providers (
down.go:140-165). For a mixed-provider project this is dangerously misleading. State that only Terraform layers are skipped, or stop the entire destroy before any layer is deleted.
"For Terraform projects, running non-interactively (in a CI/CD pipeline or with --no-prompt)" +
" without --force previews the resources that would be deleted and exits without deleting" +
" anything. Re-run with --force to delete resources without confirmation.",
Azure Dev CLI Install InstructionsInstall scriptsMacOS/Linux
bash: pwsh: WindowsPowerShell install MSI install Standalone Binary
MSIDocumentationlearn.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 method
(*provisioning.Manager).RecordInfraProviderUsage(layers)computes the value fromthe command's configured layers and records it as a usage attribute. It resolves the manager's
default provider (for layers that leave the provider unspecified) at most once per call, memoized
via
sync.OnceValues.The attribute is a sorted, de-duplicated string slice of the distinct providers the layers
resolve to:
bicep/terraform/arm/pulumi);custom— the raw name is never emitted(privacy);
["bicep"]); a multi-layer projectthat combines providers records each distinct value (e.g.
["bicep","terraform"]), preservingwhich providers were combined rather than collapsing to a lossy
mixedmarker.Because bucketing happens before de-duplication, two different extension providers collapse to a
single
["custom"](the raw names are never distinguished).It is invoked once per command, early (before provider work), from the lifecycle actions:
provision: inProvisionAction.Run, before the--preview+ multi-layer validation (coverspreview, validation-failure, failure, and success);
up: inupAction.Run, before manager initialization and the custom-workflow branch, so everyuppath is covered — including init failures and customworkflows.up(see below);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 never receives it — the value is attached directly to spans (not theprocess-global usage bag), so it stays on
cmd.provision/cmd.uponly.For
up, recording happens on the commonupAction.Runpath — before manager initialization andthe custom-workflow branch — so it covers every
uppath (initialization failures, customworkflows.up, and the unified graph) rather than only the unified-graph path. It is attacheddirectly to the
cmd.upspan (not the process-global usage bag), so a customworkflows.upcmd.upspan is tagged while the
azd package/provision/deployin-process child commands it spawnskeep their own provider attribution on their own spans — the parent value is never leaked onto, nor
overwritten by, those children. The unified-graph runner additionally tags the synthetic
cmd.provisionspan the same way.infra generate/synthemit the value read fromazure.yaml'sinfra.provideras a singlestring (or
autowhen unset), now routed through the samecustombucketing so a non-built-in(extension) provider name is never emitted raw; the slice representation remains specific to the
provision/up/down path.
Telemetry governance
fields.InfraProviderKey(no new field;SystemMetadata/FeatureInsight);refreshed its source doc comment for the value domain and scalar-vs-slice split.
feature-telemetry-matrix.md,telemetry-schema.md, andtelemetry-data.mdfor the valuedomain and the provision/up/down (slice) vs generate/synth (scalar) distinction, including a
"Data Nuances & Gotchas" note documenting the type-polymorphic, multi-valued schema.
commandsWithSpecificTelemetrycomments intelemetry_test.go.Privacy / downstream review (single-value → array)
Changing
infra.providerfrom scalar-only tostring | string[]triggers the mandatory downstreamreview in
docs/specs/metrics-audit/privacy-review-checklist.md. Reviewers must confirm thefollowing before merge:
infra.providerhandle both scalar and array shapesinfra.providerare updatedCustomerContentexposure — extension provider names remain bucketed tocustomTests
TestRecordInfraProviderUsage— single / default / uniform / different-providers-as-slice /custom-bucketed / two-custom→
["custom"]/ built-in+custom / empty / nil-resolver /failing-resolver / resolver→NotSpecified.
TestUsageAttributesExcluding— thecmd.packagespan filter.Test_CLI_Telemetry_NestedCommands— assertsinfra.provideris present oncmd.up/cmd.provisionand absent from the syntheticcmd.packagespan (trace-level coverage).Verification
go build ./...,gofmt -lclean.go test ./pkg/infra/provisioning/,./internal/cmd/,./cmd/(telemetry + up + down).