Files
suaveplan/packages/persistence/storage/storage-browser-opfs/src/otel/otel.md
2026-05-27 23:47:53 +01:00

2.7 KiB

otel — OpenTelemetry instrumentation for OPFS storage

(no submodules)

Purpose

Centralises every metric, histogram, and span emitted by OpfsStorage behind a single lazy instrument factory. Lazy construction lets consumers install a custom global MeterProvider / TracerProvider before the storage path executes, and lets tests pin a real in-memory MeterProvider against which the recorded attribute set is asserted. The module exposes a small recordOp({op, outcome, durationMs, bytes?, direction?}) helper that every operation in the storage class calls once.

Features

  • Six instruments: 4 counters (reads_total, writes_total, deletes_total, errors_total) and 2 histograms (op_duration_ms, io_bytes).
  • Stable label space: {op, outcome} on every counter / duration, {op, direction} on io_bytes.
  • Aborted operations count toward errors_total with outcome: "aborted" so SLO dashboards can split them out.
  • setStorageBrowserOpfsMeterProvider(provider) for runtime provider injection (used by @suaveplan/opentelemetry).
  • resetInstruments() rebuilds the cache between test blocks.

Usage: Basic Example

import { recordOp } from "@suaveplan/storage-browser-opfs/otel";

recordOp({ op: "set", outcome: "success", durationMs: 12, bytes: 100, direction: "write" });

Usage: Advanced Example

import { metrics } from "@opentelemetry/api";
import {
    getInstruments,
    setStorageBrowserOpfsMeterProvider,
    resetInstruments,
} from "@suaveplan/storage-browser-opfs/otel";

// In a Bun/Node test:
class CapturingMeterProvider { /* real in-memory MeterProvider */ }
const provider = new CapturingMeterProvider();
setStorageBrowserOpfsMeterProvider(provider);
resetInstruments();
const { writesTotal } = getInstruments(true);
writesTotal.add(1, { op: "set", outcome: "success" });

API Reference

  • setStorageBrowserOpfsMeterProvider(provider | undefined): void.
  • getInstruments(force?: boolean): StorageBrowserOpfsInstruments — cached unless force is true.
  • recordOp(input: RecordOpInput): void.
  • resetInstruments(): void.
  • Types: StorageBrowserOpfsOp (14 op names), StorageBrowserOpfsOpOutcome (success | error | aborted), RecordOpInput.

Implementation Notes

The dispatch in recordOp is intentionally a flat if/else chain rather than a lookup table: TypeScript can statically verify exhaustiveness over StorageBrowserOpfsOp, and the cost of a 14-arm chain is negligible compared to the underlying counter add. aborted outcomes are routed to errors_total (not a separate counter) on purpose — operationally they're failures from the caller's perspective even though they're not exceptions on the server side.