first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
# telemetry
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Provides the shared OpenTelemetry meter and instrument set used by every
public entry point of `@suaveplan/email-processing`. Instruments are
constructed lazily on first call, then cached so each metric is bound
exactly once per process — this is what makes the package's
spec-conformance test (which runs against a real `MeterProvider` +
`InMemoryMetricExporter`) deterministic. There are no mocks: the test
setup installs a real meter provider before any source module imports.
## Features
- Lazy, idempotent singleton (`getEmailProcessingInstruments`) with an
explicit test-only `resetEmailProcessingInstruments` for re-binding
after a fresh meter provider is installed in setup.
- Stable instrument names under the `email_processing.*` prefix.
- Six counters and one histogram covering parse counts, parse
failures, attachment outcomes, attachment extraction duration, hook
invocations, DKIM/SPF/DMARC outcomes, spam classification counts,
and thread grouping counts.
- Strictly typed `EmailProcessingInstruments` interface — counter
misuses become typecheck errors at the call site.
## Usage: Basic
```ts
import { getEmailProcessingInstruments } from "@suaveplan/email-processing/otel";
const m = getEmailProcessingInstruments();
m.parseCounter.add(1);
```
## Usage: Advanced
```ts
import {
getEmailProcessingInstruments,
resetEmailProcessingInstruments,
} from "@suaveplan/email-processing/otel";
// In a test setup file:
resetEmailProcessingInstruments();
const meter = getEmailProcessingInstruments();
const start = performance.now();
await processAttachments(parsed.attachments);
meter.attachmentExtractionDurationMs.record(performance.now() - start, {
"attachment.count": parsed.attachments.length,
});
```
## API Reference
- `EmailProcessingInstruments` — readonly interface listing every
counter and histogram, plus the underlying `meter`.
- `getEmailProcessingInstruments(): EmailProcessingInstruments` — returns
the cached instrument set, building it on first call.
- `resetEmailProcessingInstruments(): void` — clears the cache so the
next `getEmailProcessingInstruments()` rebuilds against whatever
`MeterProvider` is currently registered via `metrics.setGlobal*`.
## Implementation Notes
The instruments are constructed against `metrics.getMeter(...)`, which
defers to whichever `MeterProvider` was last installed via
`metrics.setGlobalMeterProvider`. Tests install an
`InMemoryMetricExporter`-backed provider in `tests/setup/polyfills.ts`
before any source module loads; production code installs a real
exporter via the application bootstrap. The histogram unit is `"ms"`
and intentionally simple: the package emits durations in milliseconds
from `performance.now()` deltas, so dashboards can read directly without
unit conversion.