import { type Counter, type Histogram, metrics } from "@opentelemetry/api"; /** * Bundle of OpenTelemetry instruments emitted by the export plugin. * * - `jobsTotal` — incremented once per job outcome, labelled * `{ outcome: "completed" | "failed" }`. * - `rowsTotal` — total rows emitted across successful jobs. * - `bytesTotal` — total bytes emitted across successful jobs. * - `durationMs` — histogram of wall-clock duration of a single * export, in milliseconds. * - `downloadServed` — incremented once per successful download * response, labelled `{ format: "csv" | "json" | "xlsx" }`. * - `downloadFailed` — incremented once per failed download * response, labelled `{ reason: "not-found" | "not-ready" | * "provider-not-found" | "failed" }`. */ export interface ExportInstruments { readonly jobsTotal: Counter; readonly rowsTotal: Counter; readonly bytesTotal: Counter; readonly durationMs: Histogram; readonly downloadServed: Counter; readonly downloadFailed: Counter; } let cached: ExportInstruments | undefined; /** * Lazily build (and cache) the export instruments bundle against the * current global `MeterProvider`. Tests call {@link resetExportInstruments} * in setup to force a re-bind against a freshly-installed provider. */ export function getExportInstruments(): ExportInstruments { if (cached !== undefined) return cached; const meter = metrics.getMeter("@suaveplan/api-plugin-export"); cached = { jobsTotal: meter.createCounter("export.jobs_total", { description: "Total export jobs by outcome.", }), rowsTotal: meter.createCounter("export.rows_total", { description: "Total rows successfully exported.", }), bytesTotal: meter.createCounter("export.bytes_total", { description: "Total bytes successfully exported.", }), durationMs: meter.createHistogram("export.duration_ms", { description: "Wall-clock duration of a single export, in ms.", unit: "ms", }), downloadServed: meter.createCounter("export.download.served", { description: "Total download responses served by format.", }), downloadFailed: meter.createCounter("export.download.failed", { description: "Total download responses that failed by reason.", }), }; return cached; } /** * Drop the cached instrument bundle so the next * {@link getExportInstruments} call rebinds against the global * `MeterProvider` in effect at that point. Tests call this after * installing a fresh `MeterProvider`. */ export function resetExportInstruments(): void { cached = undefined; }