Documentation
¶
Overview ¶
Package observability is wowapi's observability port: the Metrics interface (RED signals + generic counters and gauges) and a no-op safe default. Third-party client libraries live in adapters/metrics/*; this package imports only the standard library and kernel-siblings.
Wiring (composition root):
var m observability.Metrics = observability.NoOp // default — no adapter wired
m = promadapter.New() // swap in the real adapter
httpx.Chain(handler, httpx.RequestID(), httpx.Recover(log),
observability.Requests(m), observability.AccessLog(log))
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AccessLog ¶
func AccessLog(logger *slog.Logger) httpx.Middleware
AccessLog returns a httpx.Middleware that emits one structured INFO line per request carrying: request_id (from httpx.RequestIDFrom), method, route (r.Pattern), status, dur_ms, and bytes. Allocations are limited to the slog call itself.
Position in the chain alongside Requests:
httpx.Chain(handler, httpx.RequestID(), httpx.Recover(log),
observability.Requests(m), observability.AccessLog(log))
func Requests ¶
func Requests(m Metrics) httpx.Middleware
Requests returns a httpx.Middleware that records RED (Rate, Errors, Duration) metrics for every request via m.ObserveRequest.
The route label is taken from r.Pattern (populated by net/http.ServeMux in Go 1.22+); the method prefix ("GET ") is stripped because method is already a separate label. When r.Pattern is empty (handler not dispatched by a pattern-aware mux) the label falls back to "unknown", keeping cardinality bounded.
Position in the chain — after RequestID and Recover (which must be outermost), wrapping the handler tightly:
httpx.Chain(handler, httpx.RequestID(), httpx.Recover(log), observability.Requests(m))
func Trace ¶
func Trace(tr Tracer) httpx.Middleware
Trace returns a httpx.Middleware that opens a server span per request, tags it with the route/method/status/request-id, and ends it. The request context is replaced with one carrying the span so handler and downstream StartSpan calls nest under it. Zero-cost with NoOpTracer.
Position: after RequestID (so the request id is available) and Recover.
Types ¶
type Metrics ¶
type Metrics interface {
// ObserveRequest records one HTTP request (RED per route). dur is the
// wall-clock duration from first byte received to response flushed.
// respBytes is the number of bytes written to the response body.
ObserveRequest(route, method string, status int, dur time.Duration, respBytes int)
// IncCounter increments a named counter by value. labels provides
// low-cardinality dimensions. Intended for: authz denials, rate-limit
// drops, outbox dead letters, webhook breaker opens, notification
// delivery failures (blueprint 07 §9).
IncCounter(name string, value float64, labels map[string]string)
// SetGauge sets a named gauge to value. Intended for: outbox_pending,
// job queue depth, workflow open tasks, pool stats,
// outbox_dispatch_lag_seconds (blueprint 07 §9).
SetGauge(name string, value float64, labels map[string]string)
}
Metrics is the framework's metric sink. Implementations must be safe for concurrent use. All methods are hot-path cheap: no reflection, no map allocation on the call site. NoOp is the safe default when no adapter is wired so call sites never need a nil check.
var NoOp Metrics = noOp{}
NoOp is the safe-default Metrics implementation whose methods are all no-ops. Wire it when no adapter is configured so callers never check nil.
type Span ¶
type Span interface {
End()
// SetAttr attaches a low-cardinality key/value to the span.
SetAttr(key, value string)
// RecordError marks the span as errored and records the error.
RecordError(err error)
}
Span is one unit of a trace. Implementations must be safe to End exactly once.
type Tracer ¶
type Tracer interface {
// StartSpan begins a span named `name` as a child of any span in ctx and
// returns a context carrying it plus the Span to End.
StartSpan(ctx context.Context, name string) (context.Context, Span)
// Inject returns the opaque cross-process carrier (a W3C traceparent) for the
// span active in ctx, to embed in an outgoing event or job so a downstream
// process continues the same trace. It returns "" when no span is active (or
// for the NoOp tracer).
Inject(ctx context.Context) string
// Extract returns a context continuing the trace named by carrier (a
// traceparent taken from an inbound request, event, or job). ctx is returned
// unchanged when carrier is "".
Extract(ctx context.Context, carrier string) context.Context
}
Tracer is wowapi's distributed-tracing port (roadmap O1), a sibling of Metrics: the kernel depends only on this interface, and a vendor binding (OpenTelemetry) lives in adapters/tracing/*. NoOpTracer is the safe default so tracing is literally zero-cost when no adapter is wired. A span started here nests under any span already in ctx, so API → relay → worker traces connect once the adapter propagates context across process boundaries.
var NoOpTracer Tracer = noopTracer{}
NoOpTracer is the safe-default Tracer: every method is a no-op and StartSpan returns ctx unchanged, so call sites never need a nil check and disabled tracing adds no allocation.