Files
skills/docs/communication/messaging/sms/src/otel/metrics.md
2026-05-29 08:20:56 +01:00

3.0 KiB

otel/metrics

(no submodules)

Purpose

otel/metrics is the OpenTelemetry instrumentation layer for @suaveplan/sms. It owns four meter instruments — three counters and a histogram — that SmsService populates on every send, retry, and failure. Wiring observability at the package level keeps consumers free from re-defining instrument names and units, and gives downstream dashboards a stable contract to plot against.

The module reads the global MeterProvider from @opentelemetry/api. Tests that wire an in-memory exporter call refreshSmsMeters() after installing the exporter so subsequent record* calls land on the test provider rather than the load-time meter.

Features

  • sms.sent_total{channel, from_me} counter — successful sends.
  • sms.failed_total{code} counter — failed sends, tagged by error code.
  • sms.retry_total{attempt} counter — retry attempts, tagged by zero-based attempt index.
  • sms.send_duration_ms{outcome} histogram — pipeline duration in milliseconds, outcome ∈ {ok, error, aborted}.
  • refreshSmsMeters() re-resolves every instrument against the current MeterProvider for test wiring.

Usage: Basic

import {
    recordSmsSent,
    recordSmsFailed,
    recordSmsRetry,
    recordSmsSendDuration,
} from "@suaveplan/sms/otel";

const start = Date.now();
try {
    // ... send ...
    recordSmsSent("marketing", false);
    recordSmsSendDuration(Date.now() - start, "ok");
} catch (err) {
    recordSmsFailed("SMS.SEND_FAILED");
    recordSmsSendDuration(Date.now() - start, "error");
}

Usage: Advanced

import {
    MeterProvider,
    PeriodicExportingMetricReader,
    ConsoleMetricExporter,
} from "@opentelemetry/sdk-metrics";
import { metrics } from "@opentelemetry/api";
import { refreshSmsMeters } from "@suaveplan/sms/otel";

const provider = new MeterProvider({
    readers: [
        new PeriodicExportingMetricReader({
            exporter: new ConsoleMetricExporter(),
        }),
    ],
});
metrics.setGlobalMeterProvider(provider);
refreshSmsMeters(); // rebind every instrument against the new provider

API Reference

  • function recordSmsSent(channel: string, fromMe: boolean): void
  • function recordSmsFailed(code: string): void
  • function recordSmsRetry(attempt: number): void
  • function recordSmsSendDuration(durationMs: number, outcome: "ok" | "error" | "aborted"): void
  • function refreshSmsMeters(): void

Implementation Notes

Instruments are stored at module scope so the hot send path performs zero allocation per record call. The default no-op meter provided by @opentelemetry/api accepts every call silently, so packages that never install a MeterProvider pay nothing. Calling refreshSmsMeters() re-creates each instrument against the current global — necessary because instrument identity is bound to the meter instance, not the API surface. The attribute keys (channel, from_me, code, attempt, outcome) are part of the public observability contract; renames require a major version bump.