3.8 KiB
otel.ts — OpenTelemetry surface for audio-ir-loader
(no submodules)
Purpose
This module owns the loader's OpenTelemetry instrumentation. It lazily
builds a single, cached AudioIrLoaderInstruments bag bound to either the
global MeterProvider or a per-process override installed via
setAudioIrLoaderMeterProvider. The bag carries every counter and
histogram the spec requires (bytes_read_total, frames_out_total,
cache_hits_total, cache_misses_total, errors_total, plus the
load_duration_ms histogram).
The split between this module and the loader/cache modules is deliberate:
all metric definitions live here so dashboards can grep for instrument
names in one place, and the loader/cache modules call recorder helpers
(recordSuccess, recordCacheHit, recordCacheMiss, recordError)
that close over the cached bag.
Features
- Real
MeterProvideroverride for tests — no mocks; tests install an in-memory recorder viasetAudioIrLoaderMeterProvider. - Histogram + five counters covering success / cache-hit / cache-miss / error outcomes.
- Span-attribute helper
uriKindOf(uri)resolves theaudio_ir.uri_kinddimension from a URI's scheme without re-parsing the whole URI.
Usage: Basic
import {
recordSuccess,
setAudioIrLoaderMeterProvider,
} from "@suaveplan/audio-ir-loader";
import { metrics } from "@opentelemetry/api";
// In an app bootstrap:
setAudioIrLoaderMeterProvider(metrics.getMeterProvider());
recordSuccess("room", 100000, 25000, 12.5);
Usage: Advanced
Tests install a real in-memory provider that records every observation:
import {
getInstruments,
setAudioIrLoaderMeterProvider,
} from "@suaveplan/audio-ir-loader";
import type { MeterProvider } from "@opentelemetry/api";
const observed: { name: string; value: number; attrs: Record<string, unknown> }[] = [];
const provider = {
getMeter: () => ({
createCounter: (name: string) => ({
add: (v: number, a?: Record<string, unknown>) =>
observed.push({ name, value: v, attrs: a ?? {} }),
}),
createHistogram: (name: string) => ({
record: (v: number, a?: Record<string, unknown>) =>
observed.push({ name, value: v, attrs: a ?? {} }),
}),
}),
} as unknown as MeterProvider;
setAudioIrLoaderMeterProvider(provider);
getInstruments(true);
API Reference
setAudioIrLoaderMeterProvider(provider | undefined): void
Install a meter provider override. Pass undefined to revert.
getInstruments(force?: boolean): AudioIrLoaderInstruments
Lazily builds (and caches) the instrument bag.
resetInstruments(): void
Drops the cache — used between test provider swaps.
recordSuccess(family, bytes, frames, durationMs): void
Increments bytes_read_total{family} and frames_out_total{family}, then
records load_duration_ms{family, outcome:"success"}.
recordCacheHit(family, durationMs): void / recordCacheMiss(family): void
Counter + duration bookkeeping for cache outcomes.
recordError(code, family, durationMs): void
Increments errors_total{code} and records the duration with
outcome:"error".
uriKindOf(uri): "bundle" | "fallback" | "https" | "drive" | "other"
Maps a URI's leading scheme to the span-attribute dimension.
Implementation Notes
The cached instrument bag is rebuilt every time setAudioIrLoaderMeterProvider
swaps the provider — otherwise tests would observe stale instruments
bound to the previous provider's meter. The force parameter on
getInstruments exists exclusively to let tests immediately rebind
after setAudioIrLoaderMeterProvider to avoid a wasted check on the
next call. uriKindOf deliberately treats http and https identically
because callers care about the on-the-wire transport, not the TLS bit.