Files
skills/docs/media/audio-ir/audio-ir-loader/src/otel/otel.md
2026-05-29 08:20:56 +01:00

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 MeterProvider override for tests — no mocks; tests install an in-memory recorder via setAudioIrLoaderMeterProvider.
  • Histogram + five counters covering success / cache-hit / cache-miss / error outcomes.
  • Span-attribute helper uriKindOf(uri) resolves the audio_ir.uri_kind dimension 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.