Files
skills/docs/security-stack/security/otp/src/observability/metrics.md
2026-05-29 08:20:56 +01:00

2.4 KiB

observability/metrics

(no submodules)

Purpose

OpenTelemetry instrument factory + recorders for the OTP family. Emits two duration histograms (generate / verify), one outcome counter, and one error counter. All instruments are lazily resolved via metrics.getMeter so a host that swaps the global MeterProvider after import (e.g. test fixtures) still observes emissions against the intended provider.

Features

  • Histograms: otp.generate_duration_ms{type,algorithm}, otp.verify_duration_ms{type,algorithm}.
  • Counter: otp.verify_outcome_total{outcome,delta_bucket} — outcome ∈ valid | invalid, delta_bucket ∈ 0 | +-1 | +-2..N | n/a (low-cardinality).
  • Counter: otp.errors_total{code} — bucketed by stable error code.
  • resetOtpMetricsForTesting() clears the instrument cache.

Usage: Basic Example

import { recordVerify } from "@suaveplan/otp/observability";

const start = performance.now();
const r = verify(code, secret);
recordVerify("totp", "SHA1", performance.now() - start);

Usage: Advanced Example

import {
  recordGenerate,
  recordOutcome,
  resetOtpMetricsForTesting,
} from "@suaveplan/otp/observability";

beforeAll(() => {
  metrics.setGlobalMeterProvider(testProvider);
  resetOtpMetricsForTesting();
});

API Reference

  • recordGenerate(kind, algorithm, ms) — records duration histogram.
  • recordVerify(kind, algorithm, ms) — same for verify.
  • recordOutcome(outcome, delta) — increments outcome counter; delta is bucketed via deltaBucket.
  • recordOtpError(code) — increments error counter.
  • deltaBucket(delta) — pure mapping helper.
  • resetOtpMetricsForTesting() — clears the instrument cache.

Implementation Notes

The delta_bucket enum has cardinality 4 to keep dashboards cheap; emitting raw delta values would explode metric storage. The cache is module-level and lazy so the first call after an import resolves the Meter against whatever MeterProvider is current at that moment.

The four instruments are intentionally decoupled from the OTP code paths so that suppressing observability (e.g. in a security-restricted environment) is a one-line change at the call site rather than a deep refactor. The recorder helpers do nothing measurable when the global MeterProvider is the OpenTelemetry no-op default, which keeps the cost near zero in environments that do not opt in to metrics.