Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
# `telemetry`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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}`, where
`reason` covers every `InterruptionClass` plus `explicit`.
- 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
```ts
import { streamTelemetry } from "@suaveplan/react-audio-stream";
streamTelemetry.peerConnect("webrtc");
streamTelemetry.recordRtt("alice", 42);
```
## Usage: Advanced
```ts
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.