# `telemetry` _(no submodules)_ ## Purpose Owns the two OTel counters published by `@suaveplan/react-midi`: `react_midi_messages_received_total` for parsed inbound messages delivered through `port.onMessage`, and `react_midi_messages_sent_total` for outbound messages sent through `port.send`. Both counters carry a `port` attribute (the underlying `MIDIPort.id`) so downstream dashboards can break traffic out by physical device. The counters are created lazily off the global `metrics` API; under a `NoopSdk` (the default in unit tests) the `add` calls are silent no-ops. Wiring an `InMemoryMetricExporter` in a host app or test harness lets consumers verify the counter values against expected deltas without coupling to the meter provider details. ## Features - Two counters: receive-side and send-side. - Both tagged with `port: string` to break traffic out by id. - Stable instrument names; usable as Prometheus / OTLP metric ids. - Default `NoopMeter` makes telemetry safe to call from unit tests. ## Usage: Basic ```ts import { recordReceived, recordSent } from "@suaveplan/react-midi"; recordReceived("midi-in-0"); recordSent("midi-out-0"); ``` ## Usage: Advanced ```ts // In a host that wires an OTLP exporter, the counter values surface // in the dashboards as react_midi_messages_received_total{port="..."}. // // In a unit test you can swap in an InMemoryMetricExporter to assert // expected deltas without touching the global MeterProvider: import { MeterProvider } from "@opentelemetry/sdk-metrics"; import { metrics } from "@opentelemetry/api"; const provider = new MeterProvider(); metrics.setGlobalMeterProvider(provider); // counters now route to provider's readers. ``` ## API Reference - `messagesReceivedCounter: Counter` — increment via the OTel API. - `messagesSentCounter: Counter`. - `recordReceived(portId: string): void` — increment receive counter. - `recordSent(portId: string): void` — increment send counter. ## Implementation Notes The helper functions exist so call sites do not have to remember the attribute key shape. They cost one synchronous `Counter.add` each; under the default `NoopMeter` provider this is genuinely free (the meter API short-circuits a no-op call into a single property lookup).