54 lines
2.5 KiB
Markdown
54 lines
2.5 KiB
Markdown
|
|
# ADR-001: Direct logz Import for Context Helpers (Exception to Global ADR-001)
|
||
|
|
|
||
|
|
**Status:** Accepted
|
||
|
|
**Date:** 2026-03-18
|
||
|
|
|
||
|
|
## Context
|
||
|
|
|
||
|
|
Global ADR-001 states that modules receiving a logger from the application layer
|
||
|
|
should duck-type the logger injection point with a private interface (e.g.
|
||
|
|
`type Logger interface { Info(...); Error(...) }`), so the application is not forced
|
||
|
|
to import `logz` just to satisfy a concrete type.
|
||
|
|
|
||
|
|
`httpmw` follows this rule for its `Logger` interface in `logger.go`. Any struct
|
||
|
|
with the right method set satisfies it.
|
||
|
|
|
||
|
|
However, `httpmw` also calls `logz.WithRequestID` (in `requestid.go`) and
|
||
|
|
`logz.GetRequestID` (in `logger.go`) to store and read the request ID from context.
|
||
|
|
These functions use an **unexported context key type** defined inside `logz`:
|
||
|
|
|
||
|
|
```go
|
||
|
|
// inside logz — not exported
|
||
|
|
type contextKey string
|
||
|
|
const requestIDKey contextKey = "request_id"
|
||
|
|
```
|
||
|
|
|
||
|
|
A context value stored with that key can only be read back with the same key. If
|
||
|
|
`httpmw` tried to replicate the storage using its own unexported key, the values set
|
||
|
|
by `logz.WithRequestID` would be invisible to `logz.GetRequestID`, and vice-versa —
|
||
|
|
breaking the downstream `logz.Logger.WithContext` integration.
|
||
|
|
|
||
|
|
## Decision
|
||
|
|
|
||
|
|
`httpmw` imports `logz` directly for context helper access (`logz.WithRequestID`,
|
||
|
|
`logz.GetRequestID`). This is an **explicit, documented exception** to the
|
||
|
|
duck-typed Logger rule in global ADR-001.
|
||
|
|
|
||
|
|
The Logger injection point remains duck-typed (`httpmw.Logger` interface in
|
||
|
|
`logger.go`). The exception applies only to the two context functions, not to the
|
||
|
|
logger parameter of `RequestLogger`.
|
||
|
|
|
||
|
|
## Consequences
|
||
|
|
|
||
|
|
- `httpmw` has a direct module dependency on `logz` in its `go.mod`. Upgrading
|
||
|
|
`logz` is a breaking change for `httpmw` if the context helper signatures change.
|
||
|
|
- `logz.WithRequestID` and `logz.GetRequestID` form a shared context contract
|
||
|
|
between `httpmw` (which stores the ID) and `logz.Logger` (which reads it when
|
||
|
|
enriching log records). Both sides of the contract must be the same package.
|
||
|
|
- Applications that use `httpmw` without `logz` as their logger will still get
|
||
|
|
request IDs injected into the context correctly — `RequestID` middleware works
|
||
|
|
independently. The ID simply won't be picked up automatically by a non-logz logger.
|
||
|
|
- This exception must not be used as a precedent for importing logz elsewhere without
|
||
|
|
justification. The rule remains: duck-type logger injection; import logz only when
|
||
|
|
the unexported context key contract requires it.
|