# OpenTelemetry instrumentation _(no submodules)_ ## Purpose Defines the four OpenTelemetry instruments emitted by `@suaveplan/imessage-adapter` and the helpers that record onto them. Instruments are resolved against the package-named `Meter` (`@suaveplan/imessage-adapter` / `0.1.0`) so consumers can filter to just this package in their dashboards. `refreshIMessageMeters()` re-binds every instrument against the current global `MeterProvider`, which tests use to redirect emissions to an in-memory exporter. ## Features - Counter `imessage.messages_emitted_total` with `{chat_type, from_me}` attributes — incremented once per parsed message yielded by `IMessageWatcher.poll()`. - Counter `imessage.attachments_emitted_total` with `{mime_family}` — incremented once per parsed attachment. - Counter `imessage.poll_errors_total` with `{code}` — incremented on every poll-loop error, attributed by `IMESSAGE.*` code. - Histogram `imessage.poll_duration_ms` with `{outcome}` (`ok` / `error` / `aborted`) — records the wall-clock duration of every completed (or cancelled) poll tick in milliseconds. ## Usage: Basic ```ts import { recordMessageEmitted, recordPollDuration, } from "@suaveplan/imessage-adapter/otel"; recordMessageEmitted("direct", false); recordPollDuration(42, "ok"); ``` ## Usage: Advanced ```ts import { metrics } from "@opentelemetry/api"; import { refreshIMessageMeters } from "@suaveplan/imessage-adapter"; metrics.setGlobalMeterProvider(meterProvider); refreshIMessageMeters(); // re-resolve so subsequent records land on this provider ``` ## API Reference - `recordMessageEmitted(chatType: "direct" | "group", fromMe: boolean): void` - `recordAttachmentEmitted(mimeFamily: string): void` - `recordPollError(code: string): void` - `recordPollDuration(durationMs: number, outcome: "ok" | "error" | "aborted"): void` - `refreshIMessageMeters(): void` — re-bind every instrument against the current global `MeterProvider`. ## Implementation Notes The instruments are stored in mutable module-level bindings so `refreshIMessageMeters()` can swap them in-place; this is the canonical pattern used by `slack-client` and the other messaging clients. The `mime_family` attribute is computed by the caller (typically the watcher) as the first segment of the MIME type so cardinality stays bounded.