first commit
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
# `otel/instruments`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Provides the lazily-cached bundle of OpenTelemetry instruments emitted by `@suaveplan/api-plugin-database`. Every counter and histogram is created against the global `MeterProvider` resolved by `@opentelemetry/api` at first call; tests install an in-memory provider through the package's setup file and then call `resetDatabaseInstruments()` to force a rebind. Centralising the instruments in one module avoids the surface drift that comes from each call site calling `metrics.getMeter(...)` independently.
|
||||
|
||||
The bundle covers the four cross-cutting observability concerns the plugin owns: pool checkouts, pool checkins, current saturation, and query duration. Migration metrics are not duplicated here — `@suaveplan/api-migrations` ships its own `migrations.applied_total` counter through `getMigrationInstruments()`, so the plugin simply lets that package emit when it triggers the runner.
|
||||
|
||||
## Features
|
||||
|
||||
- Four instruments: two counters (`db.pool.checkouts_total`, `db.pool.checkins_total`), one up-down-counter (`db.pool.saturation`), one histogram (`db.query.duration_ms`).
|
||||
- Lazy creation so the bundle binds to whichever `MeterProvider` is global at first call.
|
||||
- `resetDatabaseInstruments()` clears the cache for test reuse.
|
||||
- Stable meter name `@suaveplan/api-plugin-database` so consumers can query by scope.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { getDatabaseInstruments } from "@suaveplan/api-plugin-database/otel/instruments";
|
||||
|
||||
const instruments = getDatabaseInstruments();
|
||||
instruments.poolCheckoutsTotal.add(1);
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
getDatabaseInstruments,
|
||||
resetDatabaseInstruments,
|
||||
} from "@suaveplan/api-plugin-database";
|
||||
|
||||
function instrumentedAcquire(pool, signal) {
|
||||
const instruments = getDatabaseInstruments();
|
||||
const start = performance.now();
|
||||
return pool.acquire(signal).then(
|
||||
(adapter) => {
|
||||
instruments.poolCheckoutsTotal.add(1);
|
||||
instruments.poolSaturation.add(1);
|
||||
instruments.queryDurationMs.record(performance.now() - start, {
|
||||
outcome: "success",
|
||||
});
|
||||
return adapter;
|
||||
},
|
||||
(err) => {
|
||||
instruments.queryDurationMs.record(performance.now() - start, {
|
||||
outcome: "error",
|
||||
});
|
||||
throw err;
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `getDatabaseInstruments()`
|
||||
|
||||
Returns `DatabaseInstruments`. First call binds against the global `MeterProvider`; subsequent calls return the same cached object (referential equality).
|
||||
|
||||
### `resetDatabaseInstruments()`
|
||||
|
||||
Drops the cache so the next `getDatabaseInstruments()` rebuilds. Call in test setup after installing an in-memory provider.
|
||||
|
||||
### `interface DatabaseInstruments`
|
||||
|
||||
Bundle of: `poolCheckoutsTotal: Counter`, `poolCheckinsTotal: Counter`, `poolSaturation: UpDownCounter`, `queryDurationMs: Histogram`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The histogram is intentionally labelled at the call site (`{ outcome }`) rather than baked into the instrument name; this keeps cardinality bounded and the OpenTelemetry shape aligned with the W3C semantic conventions.
|
||||
- The bundle does NOT include a migration counter — `@suaveplan/api-migrations` ships its own. Mixing them here would emit duplicate signals against the same meter name.
|
||||
- `metrics.setGlobalMeterProvider(provider)` BEFORE the first call is mandatory in tests; the bundle is captured at first call and reused.
|
||||
Reference in New Issue
Block a user