Files
httpmw/docs/adr/ADR-002-requestid-via-logz-context.md

51 lines
2.4 KiB
Markdown
Raw Normal View History

# ADR-002: Request ID Injected via logz Context Helpers
**Status:** Accepted
**Date:** 2026-03-18
## Context
Each HTTP request should carry a unique identifier that appears in log records,
error responses, and the `X-Request-ID` response header, so that a single request
can be traced across log lines.
There are two sub-problems:
1. **Generation and storage**: the middleware must generate an ID and make it
available to downstream code via the request context.
2. **Retrieval for logging**: `RequestLogger` must be able to read the ID from the
context to include it in log records.
The naive approach — store the ID under a locally-defined context key — breaks
interoperability with `logz.Logger.WithContext`, which enriches log records with
values stored under `logz`'s own unexported key. If a different key is used, logz
cannot find the ID, and it does not appear automatically in structured log output.
## Decision
The `RequestID` middleware calls `logz.WithRequestID(ctx, id)` to store the
generated ID in context. `RequestLogger` calls `logz.GetRequestID(r.Context())` to
retrieve it.
Both functions use the same unexported key inside the `logz` package, guaranteeing
that the value stored by `RequestID` is the same value retrieved by `RequestLogger`
and, more importantly, by any `logz.Logger` downstream that calls `WithContext`.
The ID is also written to the `X-Request-ID` response header at the middleware
level, so clients can correlate responses to requests without parsing log files.
## Consequences
- Any `logz.Logger` in the request chain that calls `.WithContext(ctx)` automatically
inherits the request ID as a structured log field — no manual plumbing required.
- The generator function is injected by the caller (`RequestID(generator func() string)`),
keeping the ID format flexible (UUID, ULID, or any string).
- If the same request ID is sent in the `X-Request-ID` request header, it is ignored
by `RequestID` — the middleware always generates a fresh ID. Preserving inbound
IDs is a separate concern that should be handled explicitly if required.
- This design requires `httpmw` to import `logz` directly (see ADR-001 for the
justification of that exception).
- Global ADR-003 (context helpers live with data owners) is directly applied here:
`logz` owns the request ID context key because the request ID is a logging
concern, not an auth or business concern.