first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
# OpenTelemetry wiring
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`otel.ts` exposes the tracer, meter, and instrument bag that every read
path in `@suaveplan/storage-uri-plugin-bundle` records against. It mirrors
the convention used by `@suaveplan/storage-uri/otel` and
`@suaveplan/storage-plugin-cache/otel`: lazy instrument acquisition,
test-injectable `MeterProvider`, and a single `recordOp` entry point that
emits the histogram, the success/error counter, and the per-op span in one
call so the call site never forgets one of the three.
The module also carries the small helpers that the rest of the package
relies on for span-attribute hygiene: `sanitiseRelPathAttr` strips
query strings and truncates to 256 chars, and `classifyRootKind` maps
a `URL` to the `file | http | data | blob | other` label used on every
span and counter.
## Features
- `bundle_uri.op_duration_ms{op, root_kind, outcome}` histogram.
- `bundle_uri.reads_total{root_kind, outcome}` counter.
- `bundle_uri.errors_total{root_kind, code}` counter.
- `bundle_uri.range_fallback_total{root_kind}` counter.
- `bundle_uri.cache_hits_total{root_kind}` and
`bundle_uri.cache_misses_total{root_kind}` counters.
- Per-op span on the `@suaveplan/storage-uri-plugin-bundle` tracer with
`bundle.package`, `bundle.rel_path`, `bundle.root_kind`,
`bundle.outcome` attributes.
- `setBundleUriMeterProvider(provider)` + `resetInstruments()` for
deterministic test injection.
## Usage: Basic
```ts
import { recordOp } from "@suaveplan/storage-uri-plugin-bundle";
recordOp({
op: "get",
rootKind: "http",
outcome: "success",
durationMs: 12,
packageSlug: "my-pkg",
relPath: "assets/x.wav",
});
```
## Usage: Advanced
```ts
import {
setBundleUriMeterProvider,
resetInstruments,
} from "@suaveplan/storage-uri-plugin-bundle";
import { MeterProvider } from "@opentelemetry/sdk-metrics";
const provider = new MeterProvider({});
setBundleUriMeterProvider(provider);
resetInstruments();
// …run instrumented code, then drain `provider` to read observations.
```
## API Reference
- `getInstruments(force?)` — lazy-build the bag; `force=true` rebuilds.
- `setBundleUriMeterProvider(provider | undefined)` — test injection.
- `resetInstruments()` — drop the cached bag.
- `recordOp(input)` — one-call emission of histogram + counter + span.
- `recordRangeFallback(rootKind)` — increment fallback counter.
- `recordCacheHit(rootKind)` / `recordCacheMiss(rootKind)` —
cache-path counters.
- `sanitiseRelPathAttr(relPath)` — strip query + truncate to 256 chars.
- `classifyRootKind(rootUrl)` — `URL` → `BundleUriRootKind`.
- `BundleUriOp`, `BundleUriOutcome`, `BundleUriInstruments`,
`RecordOpInput` — supporting types.
## Implementation Notes
The instrument bag is held in a module-private `let` so the same
instruments persist across calls. `resetInstruments` is the test-only
escape hatch that drops the cache so the next `getInstruments` rebinds
against the freshly-installed `MeterProvider`. The 256-char clip is
applied *after* the query strip — query-string lengths are not counted
against the attribute size budget. `classifyRootKind` is a `switch` over
`URL.protocol` (which always ends with `:`); the default case covers
bundler-virtual schemes (`virtual:`, `~asset:`, `\0…`) so coverage
includes the `"other"` branch.