Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
# `observability/metrics` — OTel histograms and counters
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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
```ts
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
```ts
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.