Every program built on zip now emits one log line per request through its own
luxfi/log logger — method, path, status, duration, trace and span, plus the
caller when the environment parked one — and RED metrics through luxfi/metric,
with W3C trace context joined when a request carries it, minted when it does
not, and propagated on Call with no handler code. /metrics renders the one
registry, and export speaks the shipped ZAP exporter, which is what o11y
ingests. Config.Telemetry{Addr, Off} is the only switch; the default is on.
The boundary is installed outermost by materialise, so requests that match
nothing — 404s, preflights — are still counted; per-route composition cannot
see them. Two defects the tests forced out: the status is derived from the
handler's error, because at the boundary the response still reads 200 (fiber
writes the real status after unwinding, so every refusal would have recorded
as success); and the route label reads the not-found sentinel, because an
unmatched request leaves the middleware's own registration in place and would
otherwise be indistinguishable from a real root leaf.
middleware.Logger and middleware.Telemetry are deleted, not deprecated:
telemetry an app can lack is the defect this closes.
luxfi/metric moves to v1.9.1 — v1.9.0 is the published build whose registry
constructors sit behind a build tag nothing sets, so counters accepted Inc()
into a registry nothing gathers and /metrics served empty.
Co-authored-by: Hanzo Dev <[email protected]>
zip middleware
Generic middleware for the zip framework. Auth-specific middleware
(JWT validation, identity-header stripping) lives in
github.com/hanzoai/gateway/middleware
— see "Why auth lives in gateway" below.
Available middleware
| Name | Purpose |
|---|---|
Recover() |
panic → JSON 500 |
Logger(luxlog.Logger) |
request log via luxfi/log |
RequestID() |
X-Request-Id propagation |
Timeout(d) |
per-request ctx deadline |
MaxBody(n) |
request size limit |
CORS(opts) |
standard CORS |
RateLimit(opts) |
per-key token bucket |
Telemetry(o11yClient) |
OTel span + request metrics |
Why auth lives in gateway
JWT validation + identity-header minting are the responsibility of the
gateway subsystem (per HIP-0106). Other subsystems mounted inside the
unified cloud binary trust the gateway-minted X-Org-Id header and do
NOT re-validate JWTs themselves — re-running JWT validation per-subsystem
is wasteful and risks divergent validation rules.
Subsystems that need to ASSERT the request was gateway-minted import
github.com/hanzoai/gateway and call gateway.AssertGatewayMinted(c).
Pipeline order
Recommended order for a service that mounts zip behind hanzoai/gateway:
app.Use(
middleware.Recover(), // 1. always first
middleware.RequestID(), // 2. mint request id
middleware.Logger(app.Logger()), // 3. log with request id
middleware.Telemetry(o11y), // 4. metrics
middleware.RateLimit(rlCfg), // 5. limit
middleware.CORS(corsCfg), // 6. last — close to response
)
JWT validation + identity-header stripping/minting is owned by the
gateway subsystem; see
github.com/hanzoai/gateway/middleware.