# Pagination OTel Instrumentation _(no submodules)_ ## Purpose The OTel module provides optional OpenTelemetry instrumentation for pagination operations. It exposes three instruments — a counter for request totals, a histogram for page sizes, and a histogram for encode/decode durations — using a lazy-initialisation pattern that gracefully degrades to silent no-op stubs when `@opentelemetry/api` is absent from the runtime. This makes instrumentation completely safe in environments without an OTel exporter and avoids adding a hard peer dependency on the OTel API. ## Features - `getPaginationInstruments()` — returns the singleton `PaginationInstruments` set, initialising from OTel API on first call. - `resetPaginationInstruments()` — resets the cached singleton for test isolation. - `PaginationInstruments` type — exposes `requestTotal` (counter), `pageSize` (histogram), and `encodeDecode` (histogram). - Graceful no-op fallback — all instruments are safe to call without an exporter installed. - Named instruments follow the OpenTelemetry semantic-conventions pattern: `pagination..`. ## Usage: Basic Example ```typescript import { getPaginationInstruments } from "@suaveplan/pagination/otel"; const { requestTotal, pageSize } = getPaginationInstruments(); // Record a successful cursor request requestTotal.add(1, { strategy: "cursor", outcome: "success" }); // Record that a page returned 10 items pageSize.record(10, { strategy: "cursor" }); ``` ## Usage: Advanced Example ```typescript import { getPaginationInstruments } from "@suaveplan/pagination/otel"; async function trackedFetch(cursor: string | undefined) { const { requestTotal, pageSize, encodeDecode } = getPaginationInstruments(); const t0 = performance.now(); try { const result = await fetchPage(cursor); requestTotal.add(1, { strategy: "cursor", outcome: "success" }); pageSize.record(result.items.length, { strategy: "cursor" }); encodeDecode.record(performance.now() - t0, { direction: "decode", type: "cursor" }); return result; } catch (err) { requestTotal.add(1, { strategy: "cursor", outcome: "error" }); throw err; } } ``` ## API Reference ### `getPaginationInstruments(): PaginationInstruments` Returns the singleton instrument set. On the first call, attempts to acquire a meter from `@opentelemetry/api` via dynamic `require`. If OTel is absent or has no `metrics` API, all instruments are replaced with silent stubs. The result is cached for subsequent calls. ### `resetPaginationInstruments(): void` Resets the cached instruments to `null`, forcing re-initialisation on the next `getPaginationInstruments()` call. Intended for test isolation only — do not call in production. ### `PaginationInstruments` | Field | Type | OTel instrument name | |---------------|------------------|-----------------------------------------------| | `requestTotal` | `OtelCounter` | `pagination.request.total` | | `pageSize` | `OtelHistogram` | `pagination.page.size` | | `encodeDecode` | `OtelHistogram` | `pagination.encode_decode.duration_ms` | Instruments support an optional `attributes` record (e.g., `{ strategy: "cursor", outcome: "success" }`). ## Implementation Notes Dynamic `require` is used (instead of a static import) so the module compiles without `@opentelemetry/api` in `package.json`. The try/catch wraps the entire OTel setup so any initialisation error (missing package, no `metrics` key) silently activates the no-op path. Callers do not need to check whether OTel is available — all four instrument methods (`add`, `record`) are always safe to call.