first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
# otel/instruments
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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<T>(op): Promise<T>` — wraps a `() => Promise<T>` with counter +
histogram observations; rethrows on failure.
- `InstrumentedOp<T>` — `{ model: string; operation: string; run: () => Promise<T> }`.
- `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.