first commit
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
# `otel/instruments` — OpenTelemetry instruments for the rate-limit plugin
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Builds (and caches) the bundle of OpenTelemetry instruments the
|
||||
rate-limit plugin emits on every check. Operators wiring an SDK at
|
||||
boot get accurate counters and histograms without the plugin owning
|
||||
the SDK lifecycle. Tests installing an `InMemoryMetricExporter` can
|
||||
call `resetRateLimitInstruments()` to force a re-bind against the
|
||||
freshly-installed provider, so assertions run against real meter
|
||||
output rather than a snapshot taken before the provider was swapped
|
||||
in.
|
||||
|
||||
The bundle covers the four signals operators actually alert on: total
|
||||
checks (with outcome), denials (subset of checks), check duration, and
|
||||
bypasses (with reason).
|
||||
|
||||
## Features
|
||||
|
||||
- Lazy, idempotent meter construction — first call binds against the
|
||||
global provider; subsequent calls return the cached bundle.
|
||||
- `resetRateLimitInstruments()` drops the cache so the next call
|
||||
re-binds; required for test isolation across files.
|
||||
- Counters and histograms carry stable units and descriptions so the
|
||||
collector's metadata pipeline can render dashboards correctly.
|
||||
- Compatible with `@opentelemetry/sdk-metrics` in-memory exporters,
|
||||
Prometheus exporters, and OTLP exporters out of the box.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { getRateLimitInstruments } from "@suaveplan/api-plugin-rate-limit";
|
||||
|
||||
const instruments = getRateLimitInstruments();
|
||||
instruments.checksTotal.add(1, { outcome: "allowed", routeId: "default" });
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
InMemoryMetricExporter,
|
||||
MeterProvider,
|
||||
PeriodicExportingMetricReader,
|
||||
} from "@opentelemetry/sdk-metrics";
|
||||
import { metrics } from "@opentelemetry/api";
|
||||
import {
|
||||
getRateLimitInstruments,
|
||||
resetRateLimitInstruments,
|
||||
} from "@suaveplan/api-plugin-rate-limit";
|
||||
|
||||
const exporter = new InMemoryMetricExporter(/* … */);
|
||||
const reader = new PeriodicExportingMetricReader({
|
||||
exporter,
|
||||
exportIntervalMillis: 1_000,
|
||||
});
|
||||
const provider = new MeterProvider({ readers: [reader] });
|
||||
metrics.setGlobalMeterProvider(provider);
|
||||
resetRateLimitInstruments();
|
||||
const instruments = getRateLimitInstruments();
|
||||
// every subsequent check() records into `exporter`.
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `interface RateLimitInstruments` — bundle of the four instruments:
|
||||
`checksTotal: Counter`, `denialsTotal: Counter`,
|
||||
`checkDurationMs: Histogram`, `bypassedTotal: Counter`.
|
||||
- `function getRateLimitInstruments(): RateLimitInstruments` — lazy
|
||||
accessor; returns the cached bundle bound to the current global
|
||||
meter provider.
|
||||
- `function resetRateLimitInstruments(): void` — drops the cache.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The meter name is `@suaveplan/api-plugin-rate-limit` so collectors
|
||||
can route metrics from this plugin to a dedicated scope without
|
||||
pattern-matching attribute values.
|
||||
- `checksTotal` and `denialsTotal` are intentionally overlapping —
|
||||
alerting on the rejection RATE is easier when the denominator
|
||||
(`checksTotal`) and numerator (`denialsTotal`) live in the same
|
||||
metric family.
|
||||
- The `outcome` attribute on `checksTotal` is one of
|
||||
`"allowed" | "denied" | "bypassed"`; the `routeId` attribute is the
|
||||
rule's `id` (or `"default"`); the `tenantId` attribute is present
|
||||
only when the request carried a resolved tenant.
|
||||
- Counter additions and histogram records are intentionally
|
||||
fire-and-forget — the OpenTelemetry API is non-blocking and any
|
||||
collector backpressure is the SDK's concern, not the plugin's.
|
||||
Reference in New Issue
Block a user