3.1 KiB
3.1 KiB
WebAuthn observability — metrics
(no submodules)
Purpose
Defines every OTel instrument emitted by @suaveplan/webauthn. The registry is a single bag of pre-created Histogram / Counter instances cached at module-load time so production paths can record without per-call allocation. The cache resets via resetMetricsForTesting() so a fresh in-memory MeterProvider registered in beforeEach produces deterministic assertions.
Features
- Five instruments cover every production path:
webauthn.register_duration_ms,webauthn.authenticate_duration_ms,webauthn.outcome_total,webauthn.attestation_format_total,webauthn.errors_total. - Bounded label cardinality:
outcome∈{ ok | error | aborted },op∈{ register | authenticate },fmt∈ the seven IANA-registered formats plusunknown. recordRegister/recordAuthenticatewrite both the duration histogram and the outcome counter atomically so dashboards never disagree.resetMetricsForTesting/getInstrumentsForTestingkeep test hooks out of the runtime module surface but available to spec tests.
Usage: Basic Example
import {
nowMs,
recordRegister,
} from "@suaveplan/webauthn/observability/metrics";
const start = nowMs();
try {
await doRegister();
recordRegister("ok", nowMs() - start);
} catch (err) {
recordRegister("error", nowMs() - start);
throw err;
}
Usage: Advanced Example
import { MeterProvider, InMemoryMetricExporter } from "@opentelemetry/sdk-metrics";
import { metrics } from "@opentelemetry/api";
import {
resetMetricsForTesting,
recordAttestationFormat,
} from "@suaveplan/webauthn/observability/metrics";
const exporter = new InMemoryMetricExporter();
const provider = new MeterProvider({ readers: [/* periodic reader */] });
metrics.setGlobalMeterProvider(provider);
resetMetricsForTesting();
recordAttestationFormat("packed");
const points = await exporter.collect();
API Reference
WebAuthnOutcome—"ok" | "error" | "aborted".WebAuthnOp—"register" | "authenticate".WebAuthnAttestationFmt—"packed" | "fido-u2f" | "tpm" | "android-key" | "android-safetynet" | "apple" | "none" | "unknown".recordRegister(outcome, durationMs)— record both histogram + outcome counter.recordAuthenticate(outcome, durationMs)— same for the assertion path.recordAttestationFormat(fmt)— increment dispatch counter.recordError(code)— incrementwebauthn.errors_total{code}.nowMs()— wall-clock reader.resetMetricsForTesting()/getInstrumentsForTesting()— test hooks.
Implementation Notes
- The instrument bag is lazily created on first call so the meter resolves against whatever
MeterProviderthe host application has installed. - The reset hook is mandatory because OTel meter caching makes pre-registered instruments outlive a test's MeterProvider swap; without it a second test reads metrics from the first test's exporter.
nowMs()is exposed as a function rather thanDate.nowdirectly so future tests can stub it without monkey-patchingglobalThis.Date.