Files
2026-05-27 23:47:53 +01:00

4.2 KiB

observability/metrics — OTel histograms and counters

(no submodules)

Purpose

The observability/metrics module owns the OpenTelemetry surface of @suaveplan/tpm-struct. Every public parser invocation records into one of three histograms and one of three counters; the histograms bucket wall-time by outcome (and by type / name_alg where it adds value), and the counters expose hit / error rates with low-cardinality attributes drawn from the bounded TPM_ALG, TPM_STRUCT_CODES, and PublicBranch enums. The full surface is what makes a running TPM- attestation gateway observable: a sudden spike in tpm_struct.parse_errors_total{code="TPM_STRUCT.MAGIC_INVALID"} is the canonical signal that an upstream is sending corrupted or non-TPM blobs.

Features

  • Three histograms: parse_tpms_attest_duration_ms{outcome}, parse_tpmt_public_duration_ms{type,outcome}, compute_name_duration_ms{name_alg}.
  • Three counters: parse_total{kind,outcome}, parse_errors_total{code}, alg_total{alg}.
  • Every attribute value is a bounded enum (no free-form strings).
  • Lazy instrument resolution — instruments are created on first call so consumers can install a custom MeterProvider before any module-load side effects.
  • resetTpmStructMetricsForTesting() clears the instrument cache for tests that swap the global provider between cases.

Usage: Basic Example

import { metrics } from "@opentelemetry/api";
import { parseTpmsAttest } from "@suaveplan/tpm-struct";

// Once at app boot, install your MeterProvider.
metrics.setGlobalMeterProvider(myProvider);

// Subsequent calls emit metrics automatically.
parseTpmsAttest(attestBytes);

Usage: Advanced Example

import {
    metrics,
    type Counter,
    type Histogram,
    type Meter,
    type MeterProvider,
} from "@opentelemetry/api";
import {
    parseTpmsAttest,
    resetTpmStructMetricsForTesting,
} from "@suaveplan/tpm-struct";

// In-memory provider for assertions in tests.
function recordingProvider() {
    const counters: { name: string; value: number; attrs?: Record<string, string> }[] = [];
    const histograms: typeof counters = [];
    const meter: Partial<Meter> = {
        createCounter: (name: string) =>
            ({
                add: (v: number, a?: Record<string, string>) =>
                    counters.push({ name, value: v, attrs: a }),
            }) as unknown as Counter,
        createHistogram: (name: string) =>
            ({
                record: (v: number, a?: Record<string, string>) =>
                    histograms.push({ name, value: v, attrs: a }),
            }) as unknown as Histogram,
    };
    const provider: Partial<MeterProvider> = {
        getMeter: () => meter as Meter,
    };
    return { provider: provider as MeterProvider, counters, histograms };
}

const { provider, counters, histograms } = recordingProvider();
metrics.setGlobalMeterProvider(provider);
resetTpmStructMetricsForTesting();
parseTpmsAttest(certifyBytes);
console.log(counters, histograms);

API Reference

  • recordAttestDuration(outcome, durationMs) — record a parse_tpms_attest_duration_ms observation.
  • recordPublicDuration(type, outcome, durationMs) — record a parse_tpmt_public_duration_ms observation.
  • recordNameDuration(nameAlg, durationMs) — record a compute_name_duration_ms observation.
  • recordParseDuration(kind, branchOrAlg, outcome, durationMs) — dispatch helper used by every parser.
  • recordParseTotal(kind, outcome) — increment parse_total.
  • recordParseError(err) — increment parse_errors_total{code} using the registered code when err is a TpmStructError, or "TPM_STRUCT.OTHER" otherwise (sentinel label, not a registry member).
  • recordAlgObserved(alg) — increment alg_total{alg}.
  • resetTpmStructMetricsForTesting() — clear the cached instruments.

Implementation Notes

Instruments are cached at module scope so the per-call cost stays a single Map.get. The OTHER sentinel on parse_errors_total is a defensive label — the parsers only ever throw TpmStructError, but the helper accepts unknown because library consumers may forward arbitrary failures through a wrapping function.