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,64 @@
# `otel`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`otel.ts` wires the `@suaveplan/drive-cache` meter and tracer used by every middleware intercept in `@suaveplan/drive-plugin-cache`. It exposes lazily-built `getInstruments()`, a `setDriveCacheMeterProvider` override (so tests can inject a stub provider), `resetInstruments()` for inter-test isolation, and five `recordX` helpers that pair a counter increment with a single short-lived span carrying the canonical `drive.cache.*` attributes.
The instruments are cached after the first call and rebuilt only when the provider override changes or `resetInstruments()` is called. This avoids re-creating instrument handles on the hot read path while still letting tests drive their own provider.
## Features
- `drive_cache.hits_total{namespace}` / `misses_total{namespace}` / `populations_total{namespace}` / `invalidations_total{namespace}` counters.
- `drive_cache.errors_total{namespace, op}` counter — `op ∈ {"get", "set", "delete"}`.
- `drive_cache.entry_bytes{namespace}` histogram observed on every population.
- One-span-per-event spans with `drive.cache.namespace`, `drive.cache.path`, and `drive.cache.outcome ∈ {"hit", "miss", "populated", "invalidated", "error"}` attributes.
- `setDriveCacheMeterProvider(provider)` resets the cached instruments so tests can swap providers between cases.
## Usage: Basic
```ts
import { recordHit, recordMiss, recordPopulate } from "@suaveplan/drive-plugin-cache/otel";
recordMiss("drive", "clip.mov");
recordPopulate("drive", "clip.mov", 4096);
recordHit("drive", "clip.mov");
```
## Usage: Advanced
```ts
import {
setDriveCacheMeterProvider,
resetInstruments,
recordError,
} from "@suaveplan/drive-plugin-cache/otel";
import { MeterProvider } from "@opentelemetry/sdk-metrics";
const provider = new MeterProvider();
setDriveCacheMeterProvider(provider);
recordError("drive", "set", "clip.mov");
// run assertions on provider's metric readers
setDriveCacheMeterProvider(undefined);
resetInstruments();
```
## API Reference
| Export | Shape | Description |
|---|---|---|
| `getInstruments(force?)` | `() => DriveCacheInstruments` | Lazy accessor; pass `true` to force-rebuild. |
| `resetInstruments()` | `() => void` | Clear the cached bag (test-only). |
| `setDriveCacheMeterProvider(provider)` | `(p?: MeterProvider) => void` | Swap the meter provider; auto-resets the cache. |
| `recordHit(namespace, path)` | `(string, string) => void` | Increment hits + emit `outcome="hit"` span. |
| `recordMiss(namespace, path)` | `(string, string) => void` | Increment misses + emit `outcome="miss"` span. |
| `recordPopulate(namespace, path, byteLength)` | `(string, string, number) => void` | Increment populations + observe entry size + emit `outcome="populated"` span. |
| `recordInvalidate(namespace, path)` | `(string, string) => void` | Increment invalidations + emit `outcome="invalidated"` span. |
| `recordError(namespace, op, path)` | `(string, "get" \| "set" \| "delete", string) => void` | Increment errors + emit `outcome="error"` span with `op` attribute. |
## Implementation Notes
Spans are created via `tracer.startSpan(...).end()` rather than `tracer.startActiveSpan(...)`. The middleware does its own work inside the calling async flow; the only purpose of these spans is to carry the outcome attribute for trace-backed analysis. Long-lived active spans would force every middleware intercept to thread an `OpenTelemetry.Context`, which is overkill for a cache event. Counter attribute bags are constructed inline as plain objects — V8 inlines this allocation on the hot path so the impact is undetectable.