2.8 KiB
instruments
(no submodules)
Purpose
Builds the OTel instrument bundle the header tenant resolver emits on every
resolve() invocation. Centralising instrument creation keeps the resolver
factory free of meter plumbing — the resolver simply records against the
frozen counter returned here. The counter name (api.tenant.resolves_total)
follows the API plugin system design doc §6 step 4 so a missing entry
is a spec deviation a CI gate could detect.
The instrument is wired against the OTel global meter provider by default, which falls back to a no-op implementation when no SDK is installed. Tests need not configure a provider; production hosts register their SDK once at boot and the resolver picks it up automatically.
Features
- One counter:
api.tenant.resolves_totallabelled{ resolver: "header", outcome }. outcomeattribute drawn from a closed five-value union (resolved,absent,invalid,not_found_in_registry,untrusted_source) so dashboards can break down resolver behaviour.- Optional
meterProviderinjection for tests that want a captive provider; defaults to the OTel global.
Usage: Basic
import { createHeaderResolverInstruments } from "@suaveplan/api-tenant-resolver-header/instruments";
const instruments = createHeaderResolverInstruments();
instruments.resolvesTotal.add(1, { resolver: "header", outcome: "resolved" });
Usage: Advanced
import { MeterProvider } from "@opentelemetry/sdk-metrics";
import { createHeaderResolverInstruments } from "@suaveplan/api-tenant-resolver-header/instruments";
const provider = new MeterProvider();
const instruments = createHeaderResolverInstruments({
meterProvider: provider,
});
// hook instruments.meter into a Prometheus exporter to scrape
// `api_tenant_resolves_total{resolver="header",outcome="invalid"}` etc.
API Reference
interface HeaderResolverInstruments—{ meter, resolvesTotal }.type HeaderResolveOutcome— five-value union of outcome attribute values.function createHeaderResolverInstruments(config?: { meterProvider? })— returns a frozen instrument bundle.
Implementation Notes
The bundle is frozen with Object.freeze so consumers cannot accidentally
swap the counter instance at runtime. The counter is created lazily-per-
resolver-instance rather than module-level so a host that wants different
meter providers per host instance (multi-tenant test harness) can wire each
resolver separately.
A counter — not a histogram — is the right primitive here because the
quantity being observed is the count of resolver invocations broken down by
outcome, not a duration. Resolver latency is dominated by the registry
probe; hosts that need probe latency wire a histogram around their
TenantRegistryProbe rather than expecting this package to time it.