Initial Commit
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# `instruments` — OpenTelemetry instruments for `api-plugin-example`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The reference plugin declares three OTel instruments that mirror the
|
||||
`telemetry.metrics[]` block in `plugin.json`. The instruments are
|
||||
lazily materialised against the global `MeterProvider` so the test
|
||||
setup can install an `InMemoryMetricExporter` before the first call.
|
||||
The integration suite reads the in-memory exporter to assert each
|
||||
manifest-declared instrument emits values during the run.
|
||||
|
||||
## Features
|
||||
|
||||
- `example.invoices_finalised_total` — counter, no unit.
|
||||
- `example.stripe.call_duration_ms` — histogram, `unit: "ms"`.
|
||||
- `example.outstanding_invoice_count` — counter modelling a gauge.
|
||||
- Lazy single-shot resolution — second call returns the cached object.
|
||||
- `resetExampleInstrumentsForTest` — clears the cache between suites.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { getExampleInstruments } from "@suaveplan/api-plugin-example/instruments/instruments";
|
||||
|
||||
const m = getExampleInstruments();
|
||||
m.invoicesFinalisedTotal.add(1, { tenant_id: ctx.tenantId ?? "none" });
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
The histogram is recorded around outbound Stripe calls. Wrap the
|
||||
network call to capture duration even on error:
|
||||
|
||||
```ts
|
||||
const start = performance.now();
|
||||
try {
|
||||
await stripe.charges.create({ amount, currency });
|
||||
} finally {
|
||||
m.stripeCallDurationMs.record(performance.now() - start);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `getExampleInstruments(): ExampleInstruments` — Lazy accessor.
|
||||
- `resetExampleInstrumentsForTest(): void` — Cache reset.
|
||||
- `ExampleInstruments` — `{ invoicesFinalisedTotal, stripeCallDurationMs, outstandingInvoiceCount }`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The instruments are materialised against `metrics.getMeter(METER_NAME)`
|
||||
rather than a passed-in provider so plugin code does not need to
|
||||
plumb a meter through every handler. The provider is installed once
|
||||
in `tests/setup/polyfills.ts` and the cached registry binds to it on
|
||||
first call. The cache is intentionally process-wide rather than
|
||||
per-`MeterProvider` because plugin authors typically install a global
|
||||
provider at boot and never swap it; tests that DO swap providers call
|
||||
`resetExampleInstrumentsForTest` between cases so the second call
|
||||
re-materialises against the new meter. The OTel SDK's
|
||||
`InMemoryMetricExporter` is the only test substrate that needs the
|
||||
cache reset — production paths bind to the global provider for the
|
||||
lifetime of the host process and any datapoint emitted goes through
|
||||
the same instrument instance. The histogram declares `unit: "ms"` so
|
||||
downstream Prometheus / OTLP collectors expose the unit in their
|
||||
metric metadata. The counter and the gauge-modelling counter both
|
||||
omit the `unit` field because they are dimensionless.
|
||||
Reference in New Issue
Block a user