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,85 @@
# `observability/metrics`
## Purpose
OpenTelemetry meter + instrument registry for `@suaveplan/crypto-rsa`. Stage 1
defines the full instrument set the proposal pins (so dashboards and SLOs can
be authored ahead of Stages 2-4) and wires up the parse/serialise duration
histograms and the typed-error counter — the only paths that have a hot
production call site at this stage.
The instruments are lazily constructed on first use to keep the module
import-side-effect-free; this matters because some downstream consumers
import the package without ever installing a `MeterProvider`, and constructing
real instruments against the no-op global meter is harmless but unnecessary.
## Features
- Lazy `meter()` and `instruments()` accessors — first access constructs,
subsequent accesses reuse cached instruments.
- `resetMetricsForTesting()` — drops the caches so a fresh `MeterProvider`
installed by a test takes effect.
- `recordParseDuration(format, ms)`, `recordSerializeDuration(format, ms)`,
`recordError(code)` — production helpers wrapping the instrument calls.
- `getInstrumentsForTesting()` — exposes the bag for test assertions.
- Full instrument set (8 histograms + 6 counters) declared up-front so the
metric names cannot drift between Stages.
## Usage: Basic Example
```ts
import {
recordError,
recordParseDuration,
} from "@suaveplan/crypto-rsa/observability";
const start = performance.now();
try {
parse();
recordParseDuration("pkcs1", performance.now() - start);
} catch (error) {
recordError(error.code);
throw error;
}
```
## Usage: Advanced Example
```ts
import {
getInstrumentsForTesting,
resetMetricsForTesting,
} from "@suaveplan/crypto-rsa/observability";
import { metrics } from "@opentelemetry/api";
import { MeterProvider } from "@opentelemetry/sdk-metrics";
resetMetricsForTesting();
metrics.setGlobalMeterProvider(new MeterProvider({ readers: [reader] }));
const bag = getInstrumentsForTesting();
// bag.errorsTotal, bag.outcomeTotal, …
```
## API Reference
- `recordParseDuration(format: string, durationMs: number): void`
- `recordSerializeDuration(format: string, durationMs: number): void`
- `recordError(code: string): void`
- `resetMetricsForTesting(): void`
- `getInstrumentsForTesting(): InstrumentBag`
The instrument bag carries (counters): `errorsTotal`, `outcomeTotal`,
`engineSelectedTotal`, `fingerprintTotal`, `profileViolationTotal`,
`blindingDisabledTotal`; (histograms): `verifyDurationMs`, `signDurationMs`,
`encryptDurationMs`, `decryptDurationMs`, `keygenDurationMs`,
`modpowDurationMs`, `parseDurationMs`, `serializeDurationMs`.
## Implementation Notes
The instruments are declared even though most are not yet wired into
production paths because the proposal pins them as the canonical observable
surface; declaring them lets dashboards reference the metric
names by build time, not by feature-arrival time, and prevents naming drift
when Stages 2-4 wire them up.
`resetMetricsForTesting` is the documented seam for swapping
`MeterProvider`s under test. Production code should never call it.