2.9 KiB
metrics
(no submodules)
Purpose
OpenTelemetry instrumentation surface for the JWS verify and sign hot paths. Every production code path records a histogram for wall-time latency and increments outcome-tagged counters; the error registry's recordError also fires once per typed throw so dashboards can pivot on code cardinality. The outcome attribute is bounded to a 4-value enum (success | sig_invalid | alg_not_allowed | header_invalid) so production observability backends do not blow up under attacker-controlled token streams.
Features
recordVerify(alg, outcome, durationMs)— histogram + outcome counter.recordSign(alg, "success" | "error", durationMs)— sign-side mirror.recordError(code)— typed-error counter pivoted by code.resetMetricsForTesting()— rebinds the cached instrument bag after a test installs a freshMeterProvider.getInstrumentsForTesting()— exposes the bag for assertion-time introspection.
Usage: Basic Example
import { metrics } from "@opentelemetry/api";
import { resetMetricsForTesting, compactVerify } from "@suaveplan/jws";
metrics.setGlobalMeterProvider(myInMemoryProvider);
resetMetricsForTesting();
await compactVerify(token, key, { algorithms: ["HS256"] });
// `jws.verify_duration_ms{alg=HS256, outcome=success}` has 1 sample.
Usage: Advanced Example
import { getInstrumentsForTesting, recordVerify, recordError, JWS_CODES } from "@suaveplan/jws";
const bag = getInstrumentsForTesting();
// bag.verifyDurationMs / bag.signDurationMs (Histogram)
// bag.verifyTotal / bag.signTotal (Counter)
// bag.errorTotal (Counter)
// Bypass the pipeline for an ad-hoc observation:
recordVerify("RS256", "sig_invalid", 4.2);
recordError(JWS_CODES.SIG_INVALID);
API Reference
recordVerify(alg: string, outcome: JwsVerifyOutcome, durationMs: number): voidrecordSign(alg: string, outcome: "success" | "error", durationMs: number): voidrecordError(code: string): voidnowMs(): numberresetMetricsForTesting(): voidgetInstrumentsForTesting(): InstrumentBagtype JwsVerifyOutcome = "success" | "sig_invalid" | "alg_not_allowed" | "header_invalid"
Implementation Notes
The instrument bag is cached in module scope so repeated invocations do not call metrics.getMeter on every request — that call has non-trivial overhead under the OTel SDK because it walks the provider's registry. Tests that install a fresh MeterProvider MUST call resetMetricsForTesting() in beforeEach; otherwise the cached bag stays bound to the original (no-op) provider and the test asserts against an empty histogram. The outcome enum's bounded cardinality is deliberate: an unbounded enum would let an adversarial token stream blow up the metrics backend's series count, and most OTel sinks bill by series.