first commit
This commit is contained in:
119
docs/api-stack/api/api-plugin-events/src/otel/instruments.md
Normal file
119
docs/api-stack/api/api-plugin-events/src/otel/instruments.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# instruments
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Bundles the seven OpenTelemetry counters emitted by
|
||||
`@suaveplan/api-plugin-events`. Every counter is lazily built on the
|
||||
first `getEventsInstruments()` call and cached against the global
|
||||
`MeterProvider` in effect at that point. Tests that install their own
|
||||
in-memory `MeterProvider` call `resetEventsInstruments()` before
|
||||
re-resolving the bundle so the counters bind to the freshly-installed
|
||||
provider.
|
||||
|
||||
The seven instruments form the canonical observability surface for
|
||||
the plugin: they count successful event lifecycle events (create /
|
||||
update / delete), RSVP writes partitioned by status, invitations sent,
|
||||
ICS exports served partitioned by `with` variant, and ICS export
|
||||
failures partitioned by reason.
|
||||
Histograms (e.g. route duration) are intentionally not part of the
|
||||
0.1 surface; the canonical histogram for HTTP routes lives in the
|
||||
host `@suaveplan/api` middleware layer.
|
||||
|
||||
## Features
|
||||
|
||||
- Seven `Counter`s emitted from the route handlers:
|
||||
`events.created_total`, `events.updated_total`,
|
||||
`events.deleted_total`, `events.rsvps_written_total{status}`,
|
||||
`events.invitations_sent_total`, `events.ics.served_total{with}`,
|
||||
`events.ics.failed_total{reason}`.
|
||||
- Lazily built and cached — no instrument is constructed before the
|
||||
first `getEventsInstruments()` call.
|
||||
- `resetEventsInstruments()` clears the cache so tests can re-bind
|
||||
against a fresh `MeterProvider`.
|
||||
- Stable name shape (`events.*_total`) for OTel collector scraping.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { getEventsInstruments } from "@suaveplan/api-plugin-events";
|
||||
|
||||
const inst = getEventsInstruments();
|
||||
inst.eventsCreatedTotal.add(1);
|
||||
inst.rsvpsWrittenTotal.add(1, { status: "going" });
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { metrics } from "@opentelemetry/api";
|
||||
import {
|
||||
MeterProvider,
|
||||
PeriodicExportingMetricReader,
|
||||
InMemoryMetricExporter,
|
||||
AggregationTemporality,
|
||||
} from "@opentelemetry/sdk-metrics";
|
||||
import {
|
||||
getEventsInstruments,
|
||||
resetEventsInstruments,
|
||||
} from "@suaveplan/api-plugin-events";
|
||||
|
||||
// Install a fresh in-memory exporter for assertions
|
||||
const exporter = new InMemoryMetricExporter(
|
||||
AggregationTemporality.CUMULATIVE
|
||||
);
|
||||
const provider = new MeterProvider({
|
||||
readers: [new PeriodicExportingMetricReader({ exporter })],
|
||||
});
|
||||
metrics.setGlobalMeterProvider(provider);
|
||||
resetEventsInstruments();
|
||||
|
||||
// Drive a counter and flush
|
||||
getEventsInstruments().invitationsSentTotal.add(3);
|
||||
await provider.forceFlush();
|
||||
const snapshot = exporter.getMetrics();
|
||||
// snapshot now contains `events.invitations_sent_total` with value 3
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `interface EventsInstruments`
|
||||
|
||||
- `eventsCreatedTotal: Counter` — incremented on every successful `POST /`.
|
||||
- `eventsUpdatedTotal: Counter` — incremented on every successful `PUT /:id`.
|
||||
- `eventsDeletedTotal: Counter` — incremented on every successful `DELETE /:id`.
|
||||
- `rsvpsWrittenTotal: Counter` — incremented on every successful
|
||||
`POST /:id/rsvp`, labelled by the new status (`going` /
|
||||
`maybe` / `invited` / `not_going`).
|
||||
- `invitationsSentTotal: Counter` — incremented by the count of
|
||||
newly-created invitations on every successful `POST /:id/invite`.
|
||||
- `icsServedTotal: Counter` — incremented on every successful
|
||||
`GET /:id/ics` response. Labelled by `with` (`"none"` or `"rsvps"`).
|
||||
- `icsFailedTotal: Counter` — incremented on every error response
|
||||
served by the ICS route. Labelled by `reason` (`"not_found"`,
|
||||
`"forbidden"`, `"unauthenticated"`, or `"invalid_query"`).
|
||||
|
||||
### `getEventsInstruments(): EventsInstruments`
|
||||
|
||||
Lazily build and cache the instrument bundle. Repeated calls return
|
||||
the same object reference.
|
||||
|
||||
### `resetEventsInstruments(): void`
|
||||
|
||||
Drop the cached bundle. The next `getEventsInstruments()` call
|
||||
rebinds against whatever `MeterProvider` is in effect.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The bundle uses singleton caching because OTel `Counter` objects are
|
||||
themselves bound to the meter that created them — calling
|
||||
`meter.createCounter("events.created_total")` twice does not produce a
|
||||
new metric, but it does produce a new JavaScript object that is
|
||||
slightly more expensive than the cached reference. The lazy
|
||||
construction also lets the polyfill in `tests/setup/polyfills.ts`
|
||||
install a `MeterProvider` before any source module that touches
|
||||
metrics imports is loaded, which is necessary because OTel binds the
|
||||
meter to the active provider at counter-creation time.
|
||||
Reference in New Issue
Block a user