observability

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 6, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL