3.3 KiB
telemetry
(no submodules)
Purpose
The telemetry module owns every OpenTelemetry instrument published by
@suaveplan/react-audio-stream. Concentrating the OTel surface in one
file means the session class never touches @opentelemetry/api and
tests can verify call counts by spying on a single verb-shaped object
instead of low-level meter handles. The shape matches Requirement 7 of
the parent spec — two counters, a gauge, two more counters, and a
histogram — so the runtime instrument set can be cross-checked against
the spec on every change.
Every emission is no-op until a host registers an OTel SDK provider
via @suaveplan/opentelemetry. The module-scope meter handles are
cheap (one map lookup) so we can keep them at file scope without
inflating cold-start cost.
Features
- Counter
react_audio_stream_peer_connect_total{transport}. - Counter
react_audio_stream_peer_disconnect_total{reason}, wherereasoncovers everyInterruptionClassplusexplicit. - UpDown counter
react_audio_stream_active_sessions(gauge-equivalent via OTel's synchronous up/down counter). - Counter
react_audio_stream_reconnect_attempt_total. - Counter
react_audio_stream_reconnect_failed_total. - Histogram
react_audio_stream_rtt_ms{participant}for the transport's RTT probe. - Verbs (
peerConnect,peerDisconnect, …) keep call sites tidy and give tests one knob per spec requirement.
Usage: Basic
import { streamTelemetry } from "@suaveplan/react-audio-stream";
streamTelemetry.peerConnect("webrtc");
streamTelemetry.recordRtt("alice", 42);
Usage: Advanced
import { streamTelemetry } from "@suaveplan/react-audio-stream";
class ReconnectLadder {
async run(verdict: InterruptionVerdict): Promise<void> {
for (let attempt = 1; attempt <= this.max; attempt++) {
streamTelemetry.reconnectAttempt();
try {
await this.session.connect(this.roomId);
return;
} catch {
await this.backoff(attempt);
}
}
streamTelemetry.reconnectFailed();
}
}
API Reference
interface StreamTelemetry— verb surface consumed by the session.const streamTelemetry: StreamTelemetry— singleton implementation.type DisconnectReason—"network" | "media-permission" | "signalling" | "peer" | "unknown" | "explicit".type TransportLabel—"webrtc" | "websocket" | "trystero" | "local".
Implementation Notes
OTel's Gauge requires async observable callbacks which complicates
the testable verb surface; the spec wording reads as "gauge tracks
active sessions" and OTel's UpDownCounter is the synchronous
equivalent that satisfies the same semantics — every monitoring backend
renders it as a gauge. The reason labels are constrained to the
DisconnectReason union so a typo in the call site is a compile
error rather than a silent cardinality leak. Transport labels are
constrained the same way — adding a new transport in chunk B requires
extending the union (one line) so backend dashboards stay in sync with
the code automatically. The participant id is used as a histogram
attribute even though it is high-cardinality because RTT samples are
per-peer by nature; consumers wiring a low-cardinality backend
(Prometheus) should drop the attribute via a view in their SDK
configuration rather than us removing it here.