feat(npm): observability logging and request metrics (S11 Step 22)

Part 1 of 2 of the npm hosted planStep 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.

📦 What this part adds

The npm observability implementation — per-request structured logging and request-level Prometheus metrics — wired into every npm handler.

  • instrument seam (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 as internal_server_error and logged at Error, then re-raised so the server's top-level recovery still handles the response.
  • Structured-log field helpers (logctx.go) — the canonical namespace_id, repository_id, package_name, package_version, and npm_command fields, rendered as stable string types.
  • Request metrics (metrics.go, buffered.go, internal/metrics/cardinality.go)npm_request_total, npm_request_duration_seconds, and npm_publish_tarball_size_bytes, with bounded handler/code label 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 the metrics.md / observability.md catalog say so.
  • Per-handler hookshandler.go wraps each route with the seam; the concrete package_version is stamped where each handler resolves it — publish at the attachment gate (publish_stream.go, so publish failure paths such as version_exists/quota_exceeded carry 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 in serveBlob (download.go) records internal_server_error so 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

Related to #140 (closed)

Edited by Dzmitry (Dima) Meshcharakou

Merge request reports

Loading
Loading