3.7 KiB
3.7 KiB
otel/instruments — OpenTelemetry instruments
(no submodules)
Purpose
Builds the OpenTelemetry instrument bundle emitted by the canonical
ImportService so consumers can wire production observability without
hand-rolling counter names. The bundle is a single cached object keyed
against the global MeterProvider — the first getImportInstruments()
call resolves the meter; subsequent calls return the same reference.
Tests rebind by installing their own MeterProvider, calling
resetImportInstruments(), and reading back via an InMemoryMetricExporter.
Features
- Nine instruments:
jobsTotal,rowsTotal,rowErrorsTotal,durationMs(histogram),storeWritesTotal,storeReadsTotal,sseConnected,sseEventsSent,sseDisconnected. storeWritesTotal{outcome}andstoreReadsTotal{outcome}are emitted bySurrealImportStoreon every adapter call so dashboards can split backend health from upstream import success/failure. The in-memory adapter (MemoryImportStore) does not emit; durable backends do.sseConnected,sseEventsSent{kind}, andsseDisconnected{reason}are emitted byGET /imports/:id/progressso dashboards can chart open SSE connections, frame throughput by event kind, and teardown causes (terminalcomplete/failedvs client abort).- Cached bundle — production code does not re-resolve the meter on every emit.
resetImportInstruments()drops the cache so a freshly-installedMeterProviderrebinds on the next call.- Asserted by
instruments.test.tsagainst a real in-memory exporter (no mocks).
Usage: Basic Example
import { getImportInstruments } from "@suaveplan/api-plugin-import";
const instruments = getImportInstruments();
instruments.jobsTotal.add(1, { outcome: "success" });
instruments.rowsTotal.add(42, { outcome: "success" });
instruments.durationMs.record(123);
Usage: Advanced Example
import { metrics } from "@opentelemetry/api";
import {
AggregationTemporality,
InMemoryMetricExporter,
MeterProvider,
PeriodicExportingMetricReader,
} from "@opentelemetry/sdk-metrics";
import { getImportInstruments, resetImportInstruments } from "@suaveplan/api-plugin-import";
const exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE);
const reader = new PeriodicExportingMetricReader({ exporter, exportIntervalMillis: 60_000 });
const provider = new MeterProvider({ readers: [reader] });
metrics.setGlobalMeterProvider(provider);
resetImportInstruments();
const instruments = getImportInstruments();
instruments.jobsTotal.add(1, { outcome: "success" });
await provider.forceFlush();
const collected = exporter.getMetrics();
// collected[0].scopeMetrics[0].metrics — read back the counter datapoint
API Reference
interface ImportInstruments { jobsTotal: Counter; rowsTotal: Counter; rowErrorsTotal: Counter; durationMs: Histogram; storeWritesTotal: Counter; storeReadsTotal: Counter; sseConnected: Counter; sseEventsSent: Counter; sseDisconnected: Counter }getImportInstruments(): ImportInstrumentsresetImportInstruments(): void
Implementation Notes
- The meter is named
@suaveplan/api-plugin-import— matching the package name keeps cross-package metric reports readable. - Counters carry the
outcomelabel so dashboards can split jobs/rows by success vs error without re-aggregating. - The histogram unit is set to
"ms"so OTel collectors that respect unit annotation produce labelled charts; consumers MUST emit millisecond values. - The cache is module-scoped — every consumer of the package shares the
same instrument set. This is the desired behaviour because the meter
resolves against the global
MeterProvider, which is a process-wide singleton.