Documentation
¶
Overview ¶
Package logging provides a context-aware slog handler and helpers for stamping per-request fields (request_id, user_id, vehicle_id, trace_id) onto every log line emitted while serving a request, without requiring callers to thread the logger through.
Mechanism: ContextHandler wraps any underlying slog.Handler and on every Handle() pulls registered values out of context.Context. The fields are added as top-level attributes on the record, so the existing slog.JSONHandler output gains them transparently.
HTTP middleware sets request_id (from chi) and is followed by the auth middleware (user_id) and vehicle-ownership middleware (vehicle_id). Background goroutines pass nil/Background context and simply emit log lines without those fields — no harm.
Index ¶
- func AccessLog(r *http.Request, ww middleware.WrapResponseWriter, dur time.Duration)
- func HTTPMiddleware(next http.Handler) http.Handler
- func RequestIDFromContext(ctx context.Context) string
- func TraceIDFromContext(ctx context.Context) string
- func UserIDFromContext(ctx context.Context) uuid.UUID
- func VehicleIDFromContext(ctx context.Context) string
- func WithRequestID(ctx context.Context, id string) context.Context
- func WithTraceID(ctx context.Context, tid string) context.Context
- func WithUserID(ctx context.Context, uid uuid.UUID) context.Context
- func WithVehicleID(ctx context.Context, vid string) context.Context
- type ContextHandler
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AccessLog ¶
func AccessLog(r *http.Request, ww middleware.WrapResponseWriter, dur time.Duration)
AccessLog emits one structured slog.Info line summarising an HTTP request. Split out from HTTPMiddleware so tests (and future adapters) can call it directly. Suppresses noisy paths that would otherwise dominate Loki: health probes (every readiness tick) and the live websocket upgrade (one line per packet would be insane).
func HTTPMiddleware ¶
HTTPMiddleware extracts chi's RequestID into the context (so ContextHandler can stamp it on every log line emitted while the handler runs), then emits a single structured access-log entry when the request finishes.
Place this AFTER chi's middleware.RequestID and middleware.RealIP, but BEFORE middleware.Recoverer so panics still get a log line.
func RequestIDFromContext ¶
RequestIDFromContext returns the request ID, or "" if unset.
func TraceIDFromContext ¶
TraceIDFromContext returns the trace ID, or "" if unset.
func UserIDFromContext ¶
UserIDFromContext returns the user ID, or uuid.Nil if unset.
func VehicleIDFromContext ¶
VehicleIDFromContext returns the vehicle ID, or "" if unset.
func WithRequestID ¶
WithRequestID returns a context that carries the given request ID. Empty values are not stored (avoids polluting logs with empty keys).
func WithTraceID ¶
WithTraceID returns a context that carries the given trace ID. Reserved for OpenTelemetry wire-up later; currently nothing sets it but ContextHandler will surface it whenever it appears.
func WithUserID ¶
WithUserID returns a context that carries the given user UUID. uuid.Nil is treated as unset.
Types ¶
type ContextHandler ¶
type ContextHandler struct {
// contains filtered or unexported fields
}
ContextHandler is a slog.Handler that decorates each record with request-scoped fields pulled from context.Context. It delegates formatting and IO to an inner handler.
func NewContextHandler ¶
func NewContextHandler(inner slog.Handler) *ContextHandler
NewContextHandler wraps the given handler. Pass slog.NewJSONHandler or slog.NewTextHandler as inner depending on RIVOLT_LOG_FORMAT.
func (*ContextHandler) Handle ¶
Handle decorates the record with context-scoped attributes and then delegates to the inner handler.
func (*ContextHandler) WithAttrs ¶
func (h *ContextHandler) WithAttrs(attrs []slog.Attr) slog.Handler
WithAttrs returns a new ContextHandler whose inner handler has the given attrs pre-applied.
func (*ContextHandler) WithGroup ¶
func (h *ContextHandler) WithGroup(name string) slog.Handler
WithGroup returns a new ContextHandler whose inner handler is in the given group. Note: context-derived attrs are still emitted at the record's top level, not under the group — request_id and friends should always be addressable by exact key in Loki/Grafana regardless of how nested the call site is.