# otel/instruments _(no submodules)_ ## Purpose Wires the package's OpenTelemetry metrics surface and exposes a thin `instrument(op)` helper the adapter wraps around every CRUD method. The helper records one counter point (with `outcome: "success" | "error"`) plus one histogram observation per call, so dashboards can pivot on model/operation/outcome and also see the per-operation latency distribution. ## Features - `better_auth.surrealdb.operations_total` counter — attributes: `model`, `operation`, `outcome`. - `better_auth.surrealdb.operation_duration_ms` histogram — attribute: `operation`. - Lazy meter resolution: the meter and instruments are constructed on first use (not at module load) so tests can install a real `MeterProvider` via `setGlobalMeterProvider` before the adapter begins issuing operations. - Universal: uses `performance.now()` when available, falls back to `Date.now()` when running under bundlers that strip `performance`. - `resetInstrumentsForTesting()` clears the lazy cache so a re-imported test environment resolves the new provider. ## Usage: Basic ```ts import { instrument } from "@suaveplan/better-auth-surrealdb/otel"; const row = await instrument({ model: "session", operation: "create", run: async () => insertSessionRow(), }); ``` ## Usage: Advanced ```ts import { instrument } from "@suaveplan/better-auth-surrealdb/otel"; import { metrics } from "@opentelemetry/api"; import { MeterProvider, PeriodicExportingMetricReader, InMemoryMetricExporter, AggregationTemporality } from "@opentelemetry/sdk-metrics"; // Install provider BEFORE first instrument() call: const exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE); const reader = new PeriodicExportingMetricReader({ exporter, exportIntervalMillis: 60_000 }); const provider = new MeterProvider({ readers: [reader] }); metrics.setGlobalMeterProvider(provider); await instrument({ model: "user", operation: "findOne", run: async () => ({ ok: true }) }); await provider.forceFlush(); const collected = exporter.getMetrics(); ``` ## API Reference - `instrument(op): Promise` — wraps a `() => Promise` with counter + histogram observations; rethrows on failure. - `InstrumentedOp` — `{ model: string; operation: string; run: () => Promise }`. - `AdapterOutcome` — `"success" | "error"`. - `resetInstrumentsForTesting()` — invalidates the lazy cache. ## Implementation Notes The lazy-init pattern is critical: importing OTel `metrics` at module load returns a noop meter unless `setGlobalMeterProvider` has been called by the host. Caching the meter+instruments after first use keeps subsequent calls allocation-free. `performance.now()` is preferred for sub-millisecond resolution but `Date.now()` is a correct fallback because the histogram records millisecond observations regardless.