Files
skills/docs/identity/auth/webauthn/src/observability/metrics.md
2026-05-29 08:20:56 +01:00

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 plus unknown.
  • recordRegister / recordAuthenticate write both the duration histogram and the outcome counter atomically so dashboards never disagree.
  • resetMetricsForTesting / getInstrumentsForTesting keep 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) — increment webauthn.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 MeterProvider the 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 than Date.now directly so future tests can stub it without monkey-patching globalThis.Date.