4.2 KiB
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 withstatusallowlist enforced at the call site.- Lazy-singleton accessors so no OTel cost is paid until the first use.
set*Provideroverrides for deterministic in-memory test providers;reset*to clear cached state between tests.
Usage: Basic Example
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
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
statusallowlist 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.