# Segmenter observability _(no submodules)_ ## Purpose The Segmenter formatter exports two OpenTelemetry instruments and a small in-memory state ring so spec-conformance tests can assert exact attribute payloads without standing up a full SDK exporter. The instrument names match the canonical Wave-3 formatter contract — every sibling formatter emits the same two metric names so dashboards and alerts compose cleanly across the family. ## Features - Histogram `i18n.format.segmenter.duration_ms` (unit `ms`) — per-segment wall-clock time - Counter `i18n.format.cache_hit{formatter="segmenter"}` — increments on cache reuse only - In-memory state ring (`getSegmenterMetricsState()`) for spec-conformance - `resetSegmenterMetricsState()` test-only helper ## Usage: Basic Example ```ts import { metrics } from "@opentelemetry/api"; import { MeterProvider } from "@opentelemetry/sdk-metrics"; const provider = new MeterProvider({ readers: [/* reader */] }); metrics.setGlobalMeterProvider(provider); import { segmentText } from "@suaveplan/i18n-formatter-segmenter"; segmentText("hello", "en-GB", { granularity: "word" }); // emits via your reader ``` ## Usage: Advanced Example ```ts import { describe, expect, it } from "@suaveplan/testing/runner"; import { clearSegmenterCache, segmentText, } from "@suaveplan/i18n-formatter-segmenter"; import { getSegmenterMetricsState, resetSegmenterMetricsState, } from "@suaveplan/i18n-formatter-segmenter"; it("emits histogram + cache-hit counter", () => { clearSegmenterCache(); resetSegmenterMetricsState(); segmentText("hello", "en-GB", { granularity: "word" }); segmentText("hello", "en-GB", { granularity: "word" }); const state = getSegmenterMetricsState(); expect(state.durationSamples).toHaveLength(2); expect(state.cacheHitSamples).toHaveLength(1); expect(state.durationSamples[0]?.attributes).toMatchObject({ locale: "en-GB", granularity: "word", }); }); ``` ## API Reference ### `recordSegmenterFormat(locale, granularity, durationMs): void` Records the duration histogram sample. Tags: `locale`, `granularity`. Called internally by `segmentText` / `formatSegments`. ### `recordSegmenterCacheHit(): void` Increments the cache-hit counter with the constant tag `{ formatter: "segmenter" }`. ### `getSegmenterMetricsState(): SegmenterMetricsState` Returns the in-memory ring of `durationSamples` and `cacheHitSamples`. Used by spec-conformance tests. ### `resetSegmenterMetricsState(): void` Clears both ring buffers. Test-only helper. ## Implementation Notes - The OTel meter is named `suaveplan.i18n.formatter.segmenter`. Every formatter in the family has its own meter so OTel resource attributes can be tied per-package if a consumer chooses. - `granularity` defaults to `"grapheme"` in the histogram tag when the caller omits it; `locale` is always required so it's never defaulted. - Sample dashboard query (PromQL/Grafana over OTLP): `histogram_quantile(0.99, sum(rate(i18n_format_segmenter_duration_ms_bucket[5m])) by (le, locale, granularity))` - The in-memory ring is intentionally unbounded — tests are short and call `resetSegmenterMetricsState()` between cases. A long-running test loop should call reset to avoid memory growth.