3.1 KiB
@suaveplan/websocket-gateway OTel surface
(no submodules)
Purpose
Centralises every OpenTelemetry instrument the WebSocket gateway emits — five span wrappers (connect, message, broadcast, start, stop), three counters, one up-down gauge for active rooms, and two histograms for start() and per-message dispatch latency. Splitting the OTel module out from the gateway file keeps the daemon under the 300-line cap and lets tests assert observability separately from behaviour.
Features
- Lazy meter/tracer acquisition via
@opentelemetry/api— no provider coupling. - Span helpers
withStartSpan/withStopSpan/withConnectSpan/withMessageSpan/withBroadcastSpanalways end the span viafinallyso an exception in the wrapped body cannot leak an open span. - Counter
ws_gateway.actions_total{action,outcome}records every authoritative decision (allowed/denied/error) so dashboards can chart auth/authz/rate-limit denial rates. - Counter
ws_gateway.presence_updates_total{kind}matches the proposal's required surface. - Gauge
ws_gateway.rooms_activefollows the proposal's required surface and is monotone-by-delta (+1 on room create, -1 on delete). - Histograms
ws_gateway.message_dispatch_ms{action}andws_gateway.start_duration_msfor SLO tracking.
Usage: Basic Example
import { withMessageSpan, recordDispatchDuration } from "@suaveplan/websocket-gateway";
await withMessageSpan(async () => {
const t0 = Date.now();
await dispatch(message);
recordDispatchDuration("room.broadcast", Date.now() - t0);
});
Usage: Advanced Example
import {
adjustRoomsActive,
recordAction,
recordPresenceUpdate,
withStartSpan,
} from "@suaveplan/websocket-gateway";
await withStartSpan(async () => {
await bind();
adjustRoomsActive(0);
});
// On every authoritative decision
recordAction("room.broadcast", "denied");
// On every presence transition
recordPresenceUpdate("join");
API Reference
withStartSpan/withStopSpan/withConnectSpan/withMessageSpan/withBroadcastSpan— wrap an async body in a named span.adjustRoomsActive(delta)— bump the rooms-active gauge.recordPresenceUpdate(kind)— increment the presence counter;kindis"join" | "leave" | "update".recordAction(action, outcome)— increment the actions counter;outcomeis"allowed" | "denied" | "error".recordDispatchDuration(action, ms)— push one observation to the dispatch histogram.recordStartDuration(ms)— push one observation to the start-duration histogram.
Implementation Notes
Every counter is multi-dimensional with a low-cardinality attribute set so the surface stays Prometheus/OTLP-friendly. Spans use tracer.startActiveSpan to participate in W3C context propagation; consumers reading inbound traceparent headers from clients will automatically nest the gateway's spans under the request span. The histograms clamp at zero to defend against clock skew producing negative deltas. The gauge is implemented as UpDownCounter because the gateway tracks per-event deltas, not snapshot reads.