feat(usagedata): wire the tracker into the composition root (S23 Step 3)

What

S23 Step 3 of the usage-data foundation plan: wire the internal/usagedata tracker (Step 2, !912 (merged)) into the composition root.

  • cmd/artifact-registry/wire_usagedata.go builds the tracker from cfg.UsageData and registers it as the first app.Component, so the LIFO drain stops it last: in-flight handlers and draining job tiers can still emit, and the tracker flushes after they finish. Disabled config wires the same no-op tracker unconditionally, keeping one code path and no nil checks for later tiers.
  • Tracker metrics register on the base registerer (the families bake the service prefix themselves; the prefixing wrapper would double it). docs/dev/observability.md gains the 11 S23 metric-family rows and records the base-registerer exception.
  • deriveAppShutdownTimeout becomes variadic and the call site adds the tracker's 5s drain slice to the shared app shutdown budget.
  • assembledApp.UsageData exposes the tracker as the seam Step 5's handlers will consume.

Stacked on !912 (merged) (Step 2) — this MR targets jdrpereira/s23-usage-data-foundation-step-2 and must merge after it; GitLab retargets to main automatically when !912 (merged) merges.

Spec coverage

Spec: docs/specs/S23-usage-data-collection.md

This MR owns AC-10 and the composition-level halves of AC-1/AC-7/E-4. Package-level rows are owned by the earlier steps of the same plan: Step 1 (internal/config, !910 (merged)) and Step 2 (internal/usagedata, !912 (merged)). AC-9 lands with Step 5.

Acceptance criteria

# Criterion Tests
AC-1 Disabled or absent section: Track/lifecycle succeed, no HTTP Step 2: TestNew_Disabled_Noop; this MR (composition): TestWireUsageData_DisabledBoot
AC-2 Track produces a collector POST carrying both context schemas Step 2: TestTracker_Track_EmitsBothContexts
AC-3 ar_instance_version equals app.Version, not settable Step 2: TestTracker_Track_InstanceVersionFromBuildInfo, TestAttrs_FieldSurface
AC-4 correlation_id equals the request's correlation ID Step 2: TestTracker_Track_EmitsBothContexts
AC-5 Out-of-enum kind/upstream drops + reason="validation" counter Step 2: TestTracker_Track_InvalidEnum_DropsEvent
AC-6 Forced gitlab_standard failure drops through the same path Step 2: TestTracker_Track_GitLabStandardFailure_DropsEvent
AC-7 Shutdown delivers queued events; bounded when unreachable Step 2: TestTracker_Shutdown_DrainsQueuedEvents, TestTracker_Shutdown_UnreachableCollector_ReturnsWithinBudget; this MR (composition): TestWireUsageData_TrackerRegisteredAsComponent
AC-8 Track safe under concurrent use (race detector) Step 2: TestTracker_Track_ConcurrentEmission, TestTracker_ConcurrentTrackAndShutdown
AC-9 Repository create emits exactly one first event Step 5 (first event); not in this MR
AC-10 Emitter metrics under ..._snowplow_events_*; dropped counter on the service registry This MR: TestWireUsageData_EnabledBootRegistersServiceMetrics, TestWireUsageData_MetricsEndpointServesUsageDataSeries; Step 2: TestNew_EmitterMetricsUseServicePrefix

Error cases

# Condition Tests
E-1 Invalid config (bad URL, missing fields, bad enums) fails boot Step 1: TestLoad_UsageData_ValidationRejections
E-2 Collector unreachable: retry/backoff, bounded queue, Track never blocks LabKit-owned emitter internals; bounded-shutdown half in Step 2: TestTracker_Shutdown_UnreachableCollector_ReturnsWithinBudget
E-3 Context validation failure: drop + counter + log Step 2: TestTracker_Track_InvalidEnum_DropsEvent, TestTracker_Track_UnknownPropKey_DropsEvent
E-4 Track after Shutdown: no-op, reason="stopped" counter Step 2: TestTracker_TrackAfterShutdown_DropsWithStoppedReason; this MR (composition): TestWireUsageData_TrackerRegisteredAsComponent
E-5 Process exit with queued events: events lost Accepted data loss per ADR-012; deliberately not asserted

Security considerations

# Concern Tests
S-1 No tokens, credentials, or raw PII; identity limited to org ID Step 2: TestTracker_Track_NoIdentityOrRailsScopedFields
S-2 Props allow-listed against the ADR-012 catalog Step 2: TestValidateProps, TestTracker_Track_UnknownPropKey_DropsEvent
S-3 Attrs cannot carry version, correlation ID, or identity Step 2: TestAttrs_FieldSurface, TestTracker_Track_InstanceVersionFromBuildInfo
S-4 TLS enforced for the collector outside development Step 1: TestLoad_UsageData_ValidationRejections, TestLoad_UsageData_HTTPAllowedInDevelopment
S-5 enabled = false: nothing leaves the process Step 2: TestNew_Disabled_Noop; this MR (composition): TestWireUsageData_DisabledBoot

Notes

  • The first commit is the documented test-first --no-verify carve-out; every other commit ran the full hook chain.

Related to #272 (closed)

Merge request reports

Loading
Loading