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,78 @@
# `otel/instruments` — counter + histogram per migration apply
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Lazily builds and caches the two OpenTelemetry instruments that
`@suaveplan/api-migrations` emits on every migration apply attempt:
- counter `migrations.applied_total{dialect, outcome}`
- histogram `migrations.apply_duration_ms{name}`
Lazy construction defers `metrics.getMeter(...)` until the first apply, so
the meter resolves against whatever `MeterProvider` is globally installed at
that moment — including the test in-memory provider that
`tests/setup/polyfills.ts` registers before any source module loads.
## Features
- Single `recordApply(dialect, name, durationMs, outcome)` entry point — keeps
the call-site code in `runner.ts` short and uniform regardless of success
or failure path.
- Emits both instruments on every call, so observability does not depend on
whether a migration succeeded.
- `resetMigrationInstruments()` lets the test suite discard the cached
instance between `MeterProvider` swaps.
- Counter attributes are deliberately low-cardinality (`dialect` × two
outcomes) so the time series is stable across releases.
## Usage: Basic Example
```ts
import { getMigrationInstruments } from "@suaveplan/api-migrations/otel/instruments";
const instruments = getMigrationInstruments();
instruments.recordApply("sqlite", "001_initial", 17, "success");
```
## Usage: Advanced Example
```ts
import {
getMigrationInstruments,
resetMigrationInstruments,
} from "@suaveplan/api-migrations/otel/instruments";
import { metrics } from "@opentelemetry/api";
import { MeterProvider } from "@opentelemetry/sdk-metrics";
// Swap providers between test phases — call reset to rebuild the cached
// instruments against the new meter.
metrics.setGlobalMeterProvider(new MeterProvider());
resetMigrationInstruments();
getMigrationInstruments().recordApply("postgres", "002_users", 42, "error");
```
## API Reference
- `interface MigrationInstruments { recordApply(dialect, name, durationMs,
outcome): void }`.
- `getMigrationInstruments(): MigrationInstruments` — returns the cached
instance, building it on first call against the currently registered
`MeterProvider`.
- `resetMigrationInstruments(): void` — clears the cache (test-only).
## Implementation Notes
- The module-level `instruments` cache is the only mutable state and is
scoped to the module — re-importing the module under a fresh ESM realm
yields a fresh cache, which is the desired behaviour for isolated tests.
- The counter is namespaced `migrations.applied_total`; the histogram is
namespaced `migrations.apply_duration_ms` — both names match the spec
delta literally so downstream dashboards do not need translation tables.
- Attribute cardinality: `dialect` is bounded by `MigrationDialect`
(currently four members), `outcome` is exactly two, and `name` is the
user-supplied migration basename. The histogram attribute is intentionally
`name`-only — adding `outcome` here would explode the bucket count.