Files
skills/docs/api-stack/api/api-plugin-webhook/src/otel/instruments.md
2026-05-29 08:20:56 +01:00

3.3 KiB

instruments.ts — webhook plugin OpenTelemetry instruments

(no submodules)

Purpose

Defines the four OpenTelemetry instruments emitted by the webhook plugin: two counters and two histograms covering every observable outcome of WebhookService.send. The bundle is lazily built against the process-wide MeterProvider and cached so repeat calls return the same Counter / Histogram references — this means tests can install a fresh provider, call resetWebhookInstruments(), and trust that the next getWebhookInstruments() rebinds against it. Without this seam, tests that install a MeterProvider after the first import see metrics flow to a stale meter and silently drop observations.

Features

  • Four instruments — deliveries_total, dead_letters_total, delivery_attempts, send_duration_ms.
  • Lazy + cached binding so the meter is resolved on first read, not at import time.
  • resetWebhookInstruments() for test isolation.
  • Stable namespace webhook_plugin.* to keep the plugin's metrics separate from @suaveplan/webhook-client's webhook_client.* metrics.

Usage: Basic

import { getWebhookInstruments } from "@suaveplan/api-plugin-webhook/otel/instruments";

const inst = getWebhookInstruments();
inst.deliveriesTotal.add(1, { event: "order.created", status: "delivered" });

Usage: Advanced

// Tests typically install a fresh MeterProvider, then call resetWebhookInstruments
// so the next getWebhookInstruments() rebinds against the freshly-installed provider.

import { metrics } from "@opentelemetry/api";
import {
    AggregationTemporality,
    InMemoryMetricExporter,
    MeterProvider,
    PeriodicExportingMetricReader,
} from "@opentelemetry/sdk-metrics";
import {
    getWebhookInstruments,
    resetWebhookInstruments,
} from "@suaveplan/api-plugin-webhook/otel/instruments";

const exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE);
const reader = new PeriodicExportingMetricReader({ exporter, exportIntervalMillis: 60_000 });
const provider = new MeterProvider({ readers: [reader] });
metrics.setGlobalMeterProvider(provider);
resetWebhookInstruments();

const inst = getWebhookInstruments();
inst.deliveriesTotal.add(1, { event: "evt", status: "delivered" });
await provider.forceFlush();
console.log(exporter.getMetrics());

API Reference

  • getWebhookInstruments() — returns the cached WebhookInstruments bundle, lazily binding on first call.
  • resetWebhookInstruments() — drops the cache so the next getWebhookInstruments() rebinds.
  • WebhookInstruments — { deliveriesTotal, deadLettersTotal, deliveryAttempts, sendDurationMs }.

Implementation Notes

The namespace webhook_plugin.* was chosen explicitly so dashboards and alerts can distinguish plugin-level emissions from the webhook_client.* emissions the underlying delivery library emits. The label set {event, status, endpoint_id} on deliveries_total deliberately includes endpoint_id even though it has unbounded cardinality — operators with many endpoints SHOULD aggregate at scrape time using a recording rule that drops the label. Including it at emission time means operators can debug a single endpoint without recompiling. The histograms inherit OTel's default bucket layout (no custom boundaries supplied) — operators tune via SDK views, not by editing this file.