Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
# `otel/metrics` — OpenTelemetry instrumentation
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`metrics.ts` registers four OpenTelemetry instruments under the meter name `@suaveplan/slack-client` and exports the helper functions every production path uses to record observations: `recordRequest`, `recordError`, `recordWebhook`. The module intentionally retrieves the meter once at module load AND exposes `refreshSlackMeters()` so tests can rewire the meter against a real in-memory `MeterProvider` after configuring the global provider. This keeps the production hot path free of `MeterProvider` lookups while still permitting `getMetrics()` assertions in the test suite.
## Features
- Four instruments: `slack.requests` (Counter), `slack.errors` (Counter), `slack.latency_ms` (Histogram, unit `ms`), `slack.webhook_sends` (Counter).
- Attributes — `{ method, outcome }` on requests, `{ method, code }` on errors, `{ outcome }` on webhook sends.
- Module-load resolution against `metrics.getMeter("@suaveplan/slack-client", "0.1.0")`.
- `refreshSlackMeters()` for tests to rebind after `metrics.setGlobalMeterProvider(...)`.
## Usage: Basic
```ts
import { recordRequest } from "@suaveplan/slack-client/otel/metrics";
recordRequest("chat.postMessage", "ok", 142);
```
## Usage: Advanced
```ts
import { metrics } from "@opentelemetry/api";
import {
AggregationTemporality,
InMemoryMetricExporter,
MeterProvider,
PeriodicExportingMetricReader,
} from "@opentelemetry/sdk-metrics";
import { refreshSlackMeters } from "@suaveplan/slack-client/otel/metrics";
const exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE);
const provider = new MeterProvider({
readers: [
new PeriodicExportingMetricReader({
exporter,
exportIntervalMillis: 60_000,
}),
],
});
metrics.setGlobalMeterProvider(provider);
refreshSlackMeters();
// ... run code that records ...
await provider.forceFlush();
const observed = exporter.getMetrics();
```
## API Reference
- `recordRequest(method: string, outcome: "ok" | "error", latencyMs: number): void` — increments `slack.requests` and records `slack.latency_ms`.
- `recordError(method: string, code: string): void` — increments `slack.errors`.
- `recordWebhook(outcome: "ok" | "error"): void` — increments `slack.webhook_sends`.
- `refreshSlackMeters(): void` — re-resolves every instrument against the current global meter provider.
## Implementation Notes
The instruments are held in module-scope `let` bindings (not `const`) because `refreshSlackMeters()` rebinds them after a test wires a fresh `MeterProvider`. This is the standard pattern for packages that exercise OTel in tests via a real in-memory exporter — the alternative (proxying every call through a getter) adds a per-call indirection on the production hot path. Instrument names follow the `<domain>.<metric>` convention seen in the wider ecosystem; the histogram unit is set to `"ms"` so dashboards render correctly without a unit-conversion step.