first commit
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
# `otel/instruments`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The `otel/instruments` module owns the OpenTelemetry instrument bundle
|
||||
emitted by `@suaveplan/api-plugin-campaigns`. It binds a meter under the
|
||||
`"@suaveplan/api-plugin-campaigns"` instrumentation-scope name against the
|
||||
process-global `MeterProvider` and exposes a lazily-cached factory so the
|
||||
plugin's route handlers, repositories, and lifecycle hooks share a single
|
||||
counter / histogram pair without re-resolving the meter on every call.
|
||||
|
||||
The bundle is intentionally small in Chunk A: a request-count counter and a
|
||||
request-duration histogram covering every route mounted by the plugin.
|
||||
Chunks B and C extend it (in their own modules) with per-domain instruments
|
||||
for campaign writes, suppression checks, and webhook ingestion outcomes.
|
||||
|
||||
## Features
|
||||
|
||||
- Lazy, cached meter binding — first call resolves the global meter; later
|
||||
calls return the cached bundle so handlers can record metrics in their
|
||||
hot path without provider lookup overhead.
|
||||
- `resetCampaignsApiInstruments()` hook for tests that install a fresh
|
||||
`MeterProvider` after the first cache write.
|
||||
- Counter + histogram primitives only; aggregation strategy and views are
|
||||
owned by the host's `MeterProvider`, not this package.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { getCampaignsApiInstruments } from "@suaveplan/api-plugin-campaigns";
|
||||
|
||||
const { requestsTotal, requestDurationMs } = getCampaignsApiInstruments();
|
||||
|
||||
const start = performance.now();
|
||||
try {
|
||||
await handler();
|
||||
requestsTotal.add(1, { route: "/campaigns", outcome: "ok" });
|
||||
} catch (err) {
|
||||
requestsTotal.add(1, { route: "/campaigns", outcome: "error" });
|
||||
throw err;
|
||||
} finally {
|
||||
requestDurationMs.record(performance.now() - start, {
|
||||
route: "/campaigns",
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { metrics } from "@opentelemetry/api";
|
||||
import { MeterProvider } from "@opentelemetry/sdk-metrics";
|
||||
import {
|
||||
getCampaignsApiInstruments,
|
||||
resetCampaignsApiInstruments,
|
||||
} from "@suaveplan/api-plugin-campaigns";
|
||||
|
||||
// Test set-up: rebind to a freshly-installed provider.
|
||||
const provider = new MeterProvider({ readers: [] });
|
||||
metrics.setGlobalMeterProvider(provider);
|
||||
resetCampaignsApiInstruments();
|
||||
|
||||
// The next resolve binds to `provider`, not the implicit global from
|
||||
// before the rebind.
|
||||
const bundle = getCampaignsApiInstruments();
|
||||
bundle.requestsTotal.add(1, { route: "/x", outcome: "ok" });
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `interface CampaignsApiInstruments { readonly requestsTotal: Counter; readonly requestDurationMs: Histogram }`
|
||||
- `getCampaignsApiInstruments(): CampaignsApiInstruments` — cached factory.
|
||||
- `resetCampaignsApiInstruments(): void` — drops the cache.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The cache is a module-level mutable binding. That is intentional and
|
||||
matches the upstream pattern in `@suaveplan/api-plugin-contacts`: an
|
||||
inert no-op metric is cheap to recreate, but creating one per request is
|
||||
not, so caching plus an explicit reset hook for tests is the simplest
|
||||
honest design.
|
||||
|
||||
The bundle is `readonly` so handlers cannot accidentally mutate it; the
|
||||
cache itself is mutable but only the reset hook reaches it. Reset is
|
||||
test-only — production code never invalidates the cache because the
|
||||
global provider is installed once at process start.
|
||||
Reference in New Issue
Block a user