# observability/instrumented _(no submodules)_ ## Purpose `instrumented` is the gated OpenTelemetry wrapper for `@suaveplan/testing-e2e` helpers and fixtures. When `TESTING_E2E_OTEL_ENABLED` is set, wrapped calls emit counters for invocations, histograms for durations, and span events for failures — giving a Playwright test run the same structured telemetry as a production service. When the flag is off, `instrumented` returns the original function reference unchanged so test-run cost is identical to the unwrapped case. ## Features - Gated at module import via `TESTING_E2E_OTEL_ENABLED` — no per-call env reads - Uses `@opentelemetry/api` only (no SDK) — consumers wire exporters at bootstrap - Preserves signature and return type of the wrapped function - Handles sync and async fn forms, including rejection - Zero overhead when disabled (identity pass-through) ## Usage: Basic Example ```ts import { instrumented } from "@suaveplan/testing-e2e/observability"; const navigate = instrumented("testing_e2e.navigate", async (page: Page, url: string) => { await page.goto(url); }); ``` ## Usage: Advanced Example ```ts import { instrumented } from "@suaveplan/testing-e2e/observability"; class DashboardPage { public gotoInstrumented = instrumented( "testing_e2e.page.dashboard.goto", async (page: Page) => { await page.goto("/dashboard"); await page.waitForLoadState("domcontentloaded"); } ); public filterInstrumented = instrumented( "testing_e2e.page.dashboard.filter", async (page: Page, query: string) => { await page.fill('input[name="q"]', query); await page.press('input[name="q"]', "Enter"); } ); } ``` ## API Reference ### `instrumented(name, fn): TFn` - `name` — metric name suffix; the full name becomes `testing_e2e..count` / `duration_ms` / `errors` - `fn` — any function to wrap - Returns `TFn` with the same signature; instrumented only when the env flag is set ### Environment gating `TESTING_E2E_OTEL_ENABLED` must equal `"1"` or `"true"` at module-import time. ## Implementation Notes The env check runs once at module import — flipping the variable mid-run has no effect, which avoids per-call reads in the hot path. With instrumentation enabled but no OTel SDK registered, `@opentelemetry/api` returns no-op tracers and meters, so the overhead is a single no-op counter increment. The disabled branch returns the original function reference, so V8 inlines it as if the wrapper was never there.