Loading
feat(npm): observability logging and request metrics (S11 Step 22)
Part 1 of 2 of the npm hosted plan — Step 22: observability hooks.
🗂️ Stacked MRs
Split into 2 stacked MRs to keep each within the reviewable-size guardrail. This part targets main; part 2 targets this branch (dm/npm-hosted-step-22-impl). Review and merge bottom-up.
- feat(npm): observability logging and request me... (!849 - merged) • Dzmitry (Dima) Meshcharakou • 19.2
👈 - test(npm): observability handler-wiring accepta... (!850 - merged) • Dzmitry (Dima) Meshcharakou • 19.2
📦 What this part adds
The npm observability implementation — per-request structured logging and request-level Prometheus metrics — wired into every npm handler.
instrumentseam (observe.go) — a per-route wrapper that installs a request-scoped observation holder, times the request, records exactly one request metric, and emits one structured completion log line. A panicking handler is counted asinternal_server_errorand logged at Error, then re-raised so the server's top-level recovery still handles the response.- Structured-log field helpers (
logctx.go) — the canonicalnamespace_id,repository_id,package_name,package_version, andnpm_commandfields, rendered as stable string types. - Request metrics (
metrics.go,buffered.go,internal/metrics/cardinality.go) —npm_request_total,npm_request_duration_seconds, andnpm_publish_tarball_size_bytes, with boundedhandler/codelabel domains, registered at boot beside the packument-rebuild metrics, plus their cardinality budgets. The request metrics are handler-scoped — the seam sits inside the Step 6 resolver Middleware, so resolution- and auth-phase failures are counted on the shared HTTP metrics, not here; the help text and themetrics.md/observability.mdcatalog say so. - Per-handler hooks —
handler.gowraps each route with the seam; the concretepackage_versionis stamped where each handler resolves it — publish at the attachment gate (publish_stream.go, so publish failure paths such asversion_exists/quota_exceededcarry it too, not just the success path), download (download.go) and dist-tag PUT (disttags.go) on their paths — and publish observes the committed tarball size (publish_commit.go).WriteError(transport.go) records the outcome code into the holder, and a mid-stream storage read failure inserveBlob(download.go) recordsinternal_server_errorso a backend fault is not metered as a download success.
Test coverage: the field helpers, metric registration and label-enumeration coverage (logctx_test.go, metrics_test.go), and the instrument seam's per-outcome log level, metric, and panic path (observe_test.go).
📚 References
- Plan: https://gitlab.com/gitlab-org/ops/artifact-registry/-/blob/main/docs/plans/2026-05-11-npm-hosted.md (Step 22)
- Spec: https://gitlab.com/gitlab-org/ops/artifact-registry/-/blob/main/docs/specs/S11-npm-hosted.md
Related to #140 (closed)
Edited by Dzmitry (Dima) Meshcharakou