# otel/instruments _(no submodules)_ ## Purpose OpenTelemetry instrument bundle for the vault plugin: four counters and one histogram covering the full CRUD surface. Every route handler reads the cached bundle at the start of the call, records the metric on success or failure, and forwards through to the next layer. Cached binding ensures repeated handler calls do not redundantly call `metrics.getMeter(...)` on every request. ## Features - `vault.items.created_total{outcome}` — counter incremented on every `POST /vault/items`. `outcome ∈ "success" | "failure"`. - `vault.items.read_total{outcome}` — counter incremented on every `GET /vault/items` or `GET /vault/items/:id`. - `vault.items.updated_total{outcome}` — counter incremented on every `PATCH /vault/items/:id`. - `vault.items.deleted_total{outcome}` — counter incremented on every `DELETE /vault/items/:id`. - `vault.item.size_bytes` — histogram of item body byte sizes, sampled on successful create + update. Unit `By` (bytes). - `resetVaultPluginInstruments()` clears the cache so tests can install a fresh `MeterProvider` between cases. ## Usage: Basic ```ts import { getVaultPluginInstruments } from "@suaveplan/api-plugin-vault"; const instruments = getVaultPluginInstruments(); instruments.itemsCreatedTotal.add(1, { outcome: "success" }); instruments.itemSizeBytes.record(body.length); ``` ## Usage: Advanced ```ts import { AggregationTemporality, InMemoryMetricExporter, MeterProvider, PeriodicExportingMetricReader, } from "@opentelemetry/sdk-metrics"; import { metrics } from "@opentelemetry/api"; import { getVaultPluginInstruments, resetVaultPluginInstruments, } from "@suaveplan/api-plugin-vault"; const exporter = new InMemoryMetricExporter( AggregationTemporality.CUMULATIVE ); const reader = new PeriodicExportingMetricReader({ exporter, exportIntervalMillis: 60_000, }); const provider = new MeterProvider({ readers: [reader] }); metrics.setGlobalMeterProvider(provider); resetVaultPluginInstruments(); const instruments = getVaultPluginInstruments(); instruments.itemsCreatedTotal.add(1, { outcome: "success" }); await provider.forceFlush(); const points = exporter.getMetrics(); ``` ## API Reference ### `VaultPluginInstruments` Readonly record: - `itemsCreatedTotal: Counter` - `itemsReadTotal: Counter` - `itemsUpdatedTotal: Counter` - `itemsDeletedTotal: Counter` - `itemSizeBytes: Histogram` ### `getVaultPluginInstruments(): VaultPluginInstruments` Returns the cached bundle, creating it lazily against the current global `MeterProvider`. Safe to call from hot paths — subsequent calls return the cached reference. ### `resetVaultPluginInstruments(): void` Drops the cached bundle. Used in test setup to re-bind against a freshly installed provider. ## Implementation Notes - The meter name is `@suaveplan/api-plugin-vault` — match this when configuring an exporter filter to isolate vault-plugin telemetry. - The histogram's `unit: "By"` (OTel canonical for bytes) is required for downstream tooling to recognise it as a size distribution rather than a duration. Operators visualising in Grafana SHOULD set the panel unit accordingly. - The `outcome` label is the only attribute emitted with the counters — kept low-cardinality on purpose. Per-tenant or per-route partitioning happens at the OTel-collector layer, not at the instrument site.