first commit
This commit is contained in:
63
docs/media/audio/midi/src/telemetry/telemetry.md
Normal file
63
docs/media/audio/midi/src/telemetry/telemetry.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# telemetry/telemetry
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
OpenTelemetry-shaped instrumentation for `@suaveplan/midi` without taking a runtime dependency on `@opentelemetry/api`. The module exposes structural `CounterLike` / `HistogramLike` interfaces (compatible with the real OTel counter/histogram shapes) and a default in-memory recorder for tests and embedded use. Consumers wire real OTel by passing `meter.createCounter(...)` / `meter.createHistogram(...)` directly.
|
||||
|
||||
The two instruments the package emits are: `midi_messages_decoded_total{type}` (Counter) and `midi_decode_duration_ns{type}` (Histogram). Both carry the MIDI message type as a single attribute — enough to slice dashboards by note-on rate, SysEx frequency, decode-latency outliers per category, etc.
|
||||
|
||||
## Features
|
||||
|
||||
- Zero runtime dep on `@opentelemetry/api` — structural typing only.
|
||||
- `createInMemoryTelemetry` recorder for tests, with snapshot + reset.
|
||||
- `nowNanos()` cross-runtime high-resolution timestamp.
|
||||
- `recordDecode(telemetry, type, startNs, endNs)` one-call helper that stamps both counter and histogram with the message-type attribute.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { createInMemoryTelemetry, nowNanos, recordDecode } from "@suaveplan/midi";
|
||||
|
||||
const telemetry = createInMemoryTelemetry();
|
||||
const start = nowNanos();
|
||||
// ...decode...
|
||||
recordDecode(telemetry, "noteOn", start, nowNanos());
|
||||
|
||||
console.log(telemetry.snapshot().counters.noteOn);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import type { MidiTelemetry } from "@suaveplan/midi";
|
||||
|
||||
// Bridge to real OpenTelemetry without a hard dep.
|
||||
function createOtelTelemetry(meter: {
|
||||
createCounter(name: string): { add: (n: number, attrs?: object) => void };
|
||||
createHistogram(name: string): { record: (n: number, attrs?: object) => void };
|
||||
}): MidiTelemetry {
|
||||
return {
|
||||
messagesDecoded: meter.createCounter("midi_messages_decoded_total"),
|
||||
decodeDurationNs: meter.createHistogram("midi_decode_duration_ns"),
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `CounterLike { add(value, attributes?): void }`.
|
||||
- `HistogramLike { record(value, attributes?): void }`.
|
||||
- `MidiTelemetry { messagesDecoded: CounterLike; decodeDurationNs: HistogramLike }`.
|
||||
- `createInMemoryTelemetry(): InMemoryTelemetry` — extends `MidiTelemetry` with `snapshot()` and `reset()`.
|
||||
- `MidiTelemetrySnapshot { counters: Record<string, number>; histograms: Record<string, number[]> }`.
|
||||
- `nowNanos(): number` — `performance.now() * 1e6` when available; falls back to `Date.now() * 1e6`.
|
||||
- `recordDecode(telemetry, type, startNs, endNs): void`.
|
||||
- `MIDI_TELEMETRY_NAMES` — frozen object with the canonical instrument names.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The in-memory recorder uses `Object.create(null)` for the counter / histogram backing objects so accidental `__proto__` keys cannot poison the snapshot. `nowNanos` multiplies milliseconds by `1_000_000` rather than using `process.hrtime.bigint()` because the latter is Node-only — the package is universal and must run identically in browsers. The slight precision loss (sub-microsecond) is acceptable for a coarse decode-duration histogram.
|
||||
Reference in New Issue
Block a user