Files
skills/docs/persistence/storage/storage-uri/src/otel/otel.md
2026-05-29 08:20:56 +01:00

2.5 KiB

otel

(no submodules)

Purpose

Owns the OpenTelemetry instrument bag for @suaveplan/storage-uri: meter, tracer, and the six counter + one histogram metrics emitted on every resolver operation. The module is intentionally side-effect-free at import time; instruments are created lazily on first access so tests can swap in an in-memory MeterProvider before any measurement is recorded.

The same module also owns the URI redaction helper redactUri(uri) used by StorageUriResolver.#run to strip query strings and fragments from the storage.uri span attribute before emission — presigned-URL secrets must never leak into telemetry sinks.

Features

  • Lazy instrument cache rebuilt automatically when the meter provider changes via setStorageUriMeterProvider(provider).
  • Six counters: reads_total, writes_total, deletes_total, errors_total, stream_fallback_total, buffered_write_total.
  • One histogram: op_duration_ms with {op, scheme, outcome} attributes.
  • redactUri(uri) — drops ?query and #fragment segments.

Usage: Basic

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

recordOp({ op: "read", scheme: "file", outcome: "success", durationMs: 12 });

Usage: Advanced

import { metrics } from "@opentelemetry/api";
import { setStorageUriMeterProvider, resetInstruments } from "@suaveplan/storage-uri/otel";

const provider = new MyInMemoryMeterProvider();
setStorageUriMeterProvider(provider);
resetInstruments();
// ... run resolver ops ...
const snapshot = provider.collect();

API Reference

  • setStorageUriMeterProvider(provider | undefined): void
  • getInstruments(force?: boolean): StorageUriInstruments
  • resetInstruments(): void
  • recordOp({ op, scheme, outcome, durationMs, code? }): void
  • recordStreamFallback(scheme: string): void
  • recordBufferedWrite(scheme: string): void
  • redactUri(uri: string): string
  • Types: StorageUriOp, StorageUriOutcome, RecordOpInput, StorageUriInstruments.

Implementation Notes

recordOp routes the success counter by op category (read/open/stat/ exists/list → reads, write → writes, remove → deletes) so consumers need not subscribe to seven separate counters. Errors always increment errors_total with the resolved STORAGE_URI.* code on the code attribute. The instrument cache is intentionally module-local rather than class-bound — the resolver is constructed many times in tests, but the instrument bag is provider-scoped, not resolver-scoped.