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,68 @@
# OTel instrumentation
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Single-source OTel instruments for `@suaveplan/service-discovery`. Centralising
counter/histogram/gauge creation here keeps cardinality bounded, avoids the
common bug where multiple meters get created under similar names, and gives
dashboards a single canonical set of metric IDs to chart.
## Features
- `svc_disc.registrations_total{outcome}` counter — outcomes are `registered`,
`refreshed`, `rejected` (low-cardinality enum).
- `svc_disc.queries_total` counter — incremented once per `query()` call.
- `svc_disc.query_duration_ms` histogram — wall-clock latency per query.
- `svc_disc.active_services` observable gauge — bound to a registry's `size`
getter at construction; the meter pulls on scrape.
## Usage: Basic Example
```ts
import {
recordRegistration,
recordQuery,
recordQueryDuration,
} from "@suaveplan/service-discovery";
recordRegistration("registered");
recordQuery();
recordQueryDuration(1.42);
```
## Usage: Advanced Example
```ts
import { bindActiveServicesGauge } from "@suaveplan/service-discovery";
const services = new Set<string>();
const dispose = bindActiveServicesGauge(() => services.size);
// ...later, on shutdown:
dispose();
```
## API Reference
- `recordRegistration(outcome)` — increments
`svc_disc.registrations_total{outcome}` by 1. `outcome` is the
`RegistrationOutcome` union.
- `recordQuery()` — increments `svc_disc.queries_total` by 1.
- `recordQueryDuration(ms)` — records into `svc_disc.query_duration_ms`. Values
below zero are clamped to 0.
- `bindActiveServicesGauge(getSize)` — registers an OTel observable-gauge
callback. Returns a disposer that unbinds the callback.
## Implementation Notes
The `outcome` label is restricted to three string values so dashboards can
chart success vs refresh vs rejection without unbounded cardinality. The
gauge is observable (not synchronous) because the canonical "current size"
of the registry is best read on scrape — that way no separate metric write
is required on every add/delete and the gauge cannot drift from the actual
state. `bindActiveServicesGauge` returns its own disposer so registries can
properly tear down their instrumentation on `dispose()` without leaking
callbacks across test runs.