# `otel/instruments.ts` _(no submodules)_ ## Purpose Owns the lazy-built OpenTelemetry instrument bundle (`SiteInstruments`) that every observable code path in `@suaveplan/api-plugin-site` emits to. Instruments are constructed against the global `MeterProvider` on first call and cached so each call to `getSiteInstruments()` reuses the same `Counter`/`Histogram` handles. `resetSiteInstruments()` drops the cache so tests can install a fresh `MeterProvider` and re-bind against it — the canonical suaveplan pattern used by every other plugin's OTel module. ## Features - `sitesCreatedTotal{outcome}` counter — `success` | `error`. - `sitesUpdatedTotal{kind}` counter — `settings` | `fields` | `state` | `domain`. - `domainResolutionsTotal{outcome}` counter — `hit` | `miss` | `error`. - `domainResolutionDurationMs` histogram — wall-clock ms. - `bootstrapFailedTotal` counter — incremented when `createDefaultSite` fails during an `organization:created` event. - Cache reset for test rebinding via `resetSiteInstruments()`. ## Usage: Basic ```ts import { getSiteInstruments } from "@suaveplan/api-plugin-site/otel/instruments"; const inst = getSiteInstruments(); inst.sitesCreatedTotal.add(1, { outcome: "success" }); ``` ## Usage: Advanced ```ts import { MeterProvider } from "@opentelemetry/sdk-metrics"; import { metrics } from "@opentelemetry/api"; import { getSiteInstruments, resetSiteInstruments, } from "@suaveplan/api-plugin-site/otel/instruments"; beforeAll(() => { const mp = new MeterProvider(); metrics.setGlobalMeterProvider(mp); resetSiteInstruments(); }); it("counts a resolution miss", () => { const inst = getSiteInstruments(); inst.domainResolutionsTotal.add(1, { outcome: "miss" }); }); ``` ## API Reference - `interface SiteInstruments` — five readonly handles. - `getSiteInstruments(): SiteInstruments` — lazy + cached. - `resetSiteInstruments(): void` — drop cache so the next call rebinds. ## Implementation Notes - The cache lives at module scope. Reset is required between tests that swap the global provider — without it, an old handle pinned to a destroyed provider would record forever into the void. - Metric names follow `._total` / `_duration_ms` convention so dashboards can grep across plugins consistently. - The histogram unit is `ms` so collectors can render p50/p95/p99 latency without additional conversion. - The counter / histogram handles returned by `getSiteInstruments()` are safe to retain across requests — they are thin proxies over the underlying `MeterProvider`'s metric registry, and recreating them on every call would defeat the purpose of OTel's batched export pipeline. Tests that swap providers therefore MUST call `resetSiteInstruments()` before the next read so the next handle points at the new provider. - This module avoids any side effects at import time so consumers can tree-shake it cleanly when they disable observability via a build flag — the `getMeter` call is gated behind the first invocation of `getSiteInstruments`.