Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
# `otel` — OpenTelemetry instrumentation for OPFS storage
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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
```ts
import { recordOp } from "@suaveplan/storage-browser-opfs/otel";
recordOp({ op: "set", outcome: "success", durationMs: 12, bytes: 100, direction: "write" });
```
## Usage: Advanced Example
```ts
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.