# SpritePlayerTelemetry _(no submodules)_ ## Purpose `SpritePlayerTelemetry` is the OTel-facing facade that `SpritePlayer` opens for every public invocation. It manages one tracer plus three metric instruments — a counter, an observable gauge, and a histogram — so consumers running a real OTel SDK can plug spans and metrics straight into their pipeline without any glue code in the player. The facade is constructed with a `getVoiceCount` callback rather than a direct reference to the player, so it can be unit-tested in isolation and so the gauge callback closes over a stable function reference for the lifetime of the player. ## Features - One tracer (`audio-sprite-player`) for spans named `audio-sprite-player.play`. - One counter (`audio_sprite_player.play_total`) keyed by `sprite.entry_name`. - One observable gauge (`audio_sprite_player.voices_active`) driven by the injected voice-count getter. - One histogram (`audio_sprite_player.play_duration_ms`) recorded on `complete` events. - Spans are closed via `recordSuccess` / `recordFailure`, with `error.code` attribute attached on the failure path. ## Usage: Basic Example ```ts import { SpritePlayerTelemetry } from "@suaveplan/audio-sprite-player"; const telemetry = new SpritePlayerTelemetry(() => activeVoices.size); const h = telemetry.startPlay("hit"); try { await adapter.play(/* ... */); telemetry.recordSuccess(h, { entryName: "hit" }); } catch (err) { telemetry.recordFailure(h, { entryName: "hit", errorCode: "AUDIO_SPRITE_PLAYER.PLAYBACK_FAILED", }); throw err; } ``` ## Usage: Advanced Example ```ts import { createSpritePlayer } from "@suaveplan/audio-sprite-player"; const player = createSpritePlayer({ adapter }); // Consumers wanting to inspect the live voice count without subscribing // to events can call _runGaugeCallback (the OTel SDK normally drives it). player.events.on("voice-stolen", () => { player.telemetry._runGaugeCallback(); console.log(player.telemetry.observedVoiceCount); }); // recordCompletion is also exposed for adapter authors who want to drive // the histogram from the engine-side "voice ended" signal directly. player.telemetry.recordCompletion(450, "hit"); ``` ## API Reference ### `new SpritePlayerTelemetry(getVoiceCount: () => number)` Constructs the facade. The callback is invoked by the OTel SDK whenever it polls the observable gauge. ### `startPlay(entryName): PlayTelemetryHandle` Opens a span and records the wall-clock start time. ### `recordSuccess(handle, attrs): void` Increments the counter, sets `OK` status, closes the span. ### `recordFailure(handle, attrs): void` Sets `ERROR` status, attaches `error.code` attribute when provided, closes the span. The counter is not incremented on failure (`play_total` reflects accepted plays only). ### `recordCompletion(durationMs, entryName): void` Records an observation on the duration histogram. ### `observedVoiceCount: number` Last value observed by the gauge callback. ### `_runGaugeCallback(): void` Test-visible hook that drives the gauge callback synchronously. Useful in environments without a real OTel SDK — the default `@opentelemetry/api` ships a noop SDK that never polls the gauge. ## Implementation Notes - The default `@opentelemetry/api` package provides a noop tracer and meter when no SDK is installed; this facade still records the calls correctly via the noop instruments, so calling code never has to gate on SDK presence. - The gauge callback is stored as a member so its identity is stable for the lifetime of the player; rebinding on every observation would defeat OTel's deduplication. - `recordFailure` deliberately does not increment the counter — a failed play is not a play.