# vault OTel instruments _(no submodules)_ ## Purpose `instruments.ts` is the single source of truth for OpenTelemetry instruments emitted by `@suaveplan/vault`. It exports a frozen `VaultInstruments` interface plus lazy-singleton accessors (`getVaultInstruments`, `getVaultTracer`) and test-only overrides (`setVaultMeterProvider`, `setVaultTracerProvider`, `resetVaultInstruments`, `resetVaultTracer`). Every histogram, counter, and span is **safe-by-construction**: no password, no secret key, no AUK, no item content, no vault identifier, no item id, and no key material is permitted in any attribute. Only operation labels, status enums (`status` ∈ documented allowlist), durations in ms, and counts cross the OTel boundary. This guarantees that enabling vault telemetry can never leak vault contents into a tracing backend, even when the backend is misconfigured or compromised. ## Features - `unlockDurationMs` / `lockDurationMs` / `flushDurationMs` — lifecycle latency histograms with no per-vault attributes. - `itemOpDurationMs` / `attachmentOpDurationMs` / `shareOpDurationMs` / `syncOpDurationMs` — operation latency histograms keyed by operation kind. - `lifecycleOutcomeTotal` / `itemOutcomeTotal` / `attachmentOutcomeTotal` / `shareOutcomeTotal` / `syncOutcomeTotal` — outcome counters with `status` allowlist enforced at the call site. - Lazy-singleton accessors so no OTel cost is paid until the first use. - `set*Provider` overrides for deterministic in-memory test providers; `reset*` to clear cached state between tests. ## Usage: Basic Example ```ts import { getVaultInstruments } from "@suaveplan/vault/otel/instruments"; const instruments = getVaultInstruments(); const start = Date.now(); await vault.unlock(password, secretKey); instruments.unlockDurationMs.record(Date.now() - start); instruments.lifecycleOutcomeTotal.add(1, { status: "unlocked" }); ``` ## Usage: Advanced Example ```ts import { metrics, type MeterProvider } from "@opentelemetry/api"; import { getVaultInstruments, resetVaultInstruments, setVaultMeterProvider, } from "@suaveplan/vault/otel/instruments"; // Inject an in-memory test provider for assertion-driven tests. const testProvider: MeterProvider = createInMemoryMeterProvider(); setVaultMeterProvider(testProvider); try { const instruments = getVaultInstruments(); instruments.itemOpDurationMs.record(12, { op: "create" }); instruments.itemOutcomeTotal.add(1, { op: "create", status: "success" }); // ... assert against testProvider's recorded data points ... } finally { resetVaultInstruments(); setVaultMeterProvider(undefined); } ``` ## API Reference - `interface VaultInstruments` — frozen shape of the instrument set. - `getVaultInstruments(): VaultInstruments` — lazy accessor for the cached instrument set. - `setVaultMeterProvider(provider: MeterProvider | undefined): void` — override the meter provider for tests. - `resetVaultInstruments(): void` — drop the cached instrument set. - `getVaultTracer(): Tracer` — lazy accessor for the cached tracer. - `setVaultTracerProvider(provider: TracerProvider | undefined): void` — override the tracer provider for tests. - `resetVaultTracer(): void` — drop the cached tracer. ## Implementation Notes - Histograms are recorded in milliseconds against the OTel `unit: "ms"` convention; consumers can configure histogram buckets globally via the SDK without per-instrument code. - Counters expose a documented `status` allowlist for each surface (lifecycle: `opened | unlocked | locked | denied`; items: `success | not_found | conflict | rejected`; attachments: `success | not_found | rejected`; shares: `success | not_found | revoked | rejected`; sync: `success | failed | rejected`). Call sites pass a string from this list — adding a new value requires an OpenSpec change. - Resetting a provider mid-process drops the cached singleton so subsequent `getVaultInstruments()` calls re-acquire from the new provider — used in test isolation only. - The global OTel API returns no-op instruments when no provider is registered; production code can call `getVaultInstruments()` unconditionally without performance impact when telemetry is disabled.