first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
# telemetry
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
The telemetry module is the single OpenTelemetry integration point for
`@suaveplan/audio-core`. It exposes thin, lazy helpers over `@opentelemetry/api`
so the data-model and processing entry points — plan compilation, block
processing, and streaming reads — can be traced and measured without scattering
observability boilerplate through the codebase. Every helper resolves the active
tracer or meter on each call, so instrumentation is completely inert when no
exporter is registered and never runs as an import-time side effect.
## Features
- Named span constants for the three instrumented entry points: `plan.compile`,
`process.block`, and `stream.read`.
- Named metric constants for the two counters (`audio_core_edits_total`,
`audio_core_stream_blocks_total`) and two histograms
(`audio_core_compile_duration_ms`, `audio_core_process_duration_ms`).
- `startSpan` returns a real `Span` the caller ends in a `finally` block.
- `recordCompile`, `recordProcessBlock`, and `recordStreamBlock` push metric
values through the globally-registered meter, falling back to the API's
no-op meter when none is registered.
- `now()` wraps `performance.now()` as the universal monotonic clock used for
duration measurement — no Node or browser globals leak into callers.
## Usage: Basic
```ts
import { now, recordCompile, SPAN_PLAN_COMPILE, startSpan } from "./telemetry.js";
const span = startSpan(SPAN_PLAN_COMPILE);
const started = now();
try {
// ...compile work...
} finally {
recordCompile(3, now() - started);
span.end();
}
```
## Usage: Advanced
```ts
import { recordStreamBlock, SPAN_STREAM_READ, startSpan } from "./telemetry.js";
async function* instrumentedStream(
blocks: AsyncGenerator<Float32Array[]>
): AsyncGenerator<Float32Array[]> {
const span = startSpan(SPAN_STREAM_READ);
try {
for await (const block of blocks) {
recordStreamBlock();
yield block;
}
} finally {
span.end();
}
}
```
## API Reference
- `startSpan(name: string): Span` — starts a span on the package tracer.
- `recordCompile(editCount: number, durationMs: number): void` — increments
`audio_core_edits_total` and records `audio_core_compile_duration_ms`.
- `recordProcessBlock(durationMs: number): void` — records
`audio_core_process_duration_ms`.
- `recordStreamBlock(count?: number): void` — increments
`audio_core_stream_blocks_total` (default `1`).
- `now(): number` — monotonic millisecond timestamp via `performance.now()`.
- Span name constants: `SPAN_PLAN_COMPILE`, `SPAN_PROCESS_BLOCK`,
`SPAN_STREAM_READ`.
- Metric name constants: `COUNTER_EDITS`, `COUNTER_STREAM_BLOCKS`,
`HISTOGRAM_COMPILE_DURATION`, `HISTOGRAM_PROCESS_DURATION`.
## Implementation Notes
Helpers deliberately do **not** memoise the tracer or meter. `@opentelemetry/api`
returns lightweight proxies that delegate to whichever provider is registered at
call time, so re-resolving per call costs nothing meaningful and keeps the module
correct when a provider is registered after the package was first imported —
which is the normal order in host applications and in tests. Creating a counter
or histogram by name is idempotent under a real SDK (instruments are deduplicated
by name) and a no-op under the default API meter. Because nothing executes at
module load, importing `@suaveplan/audio-core` mutates no global state.