import { logger, serializeError } from "./logger.js"; export namespace Metrics { export type DomainSources = { workers(): Promise; placements(): Promise; resolutions(): Record; /** Distinct hostname / env counts among live workers. */ worlds(): Promise<{ hostnames: number; envs: number }>; }; export type RequestTrack = { route: string; done(statusCode: number): void; }; export type Instance = { forwardsTotal: { inc(labels: { kind: string }): void }; forwardFailuresTotal: { inc(labels: { outcome: string }): void }; takeoversTotal: { inc(labels: { strategy: string; outcome: string }): void; }; degradedHeartbeatsTotal: { inc(labels: { reason: string }): void }; registerRejectionsTotal: { inc(labels: { account: string; pool: string; reason: string }): void; }; dataPlaneConnections: { inc(): void; dec(): void }; internalError(source: string): void; guarded(source: string, fn: () => unknown): () => void; trackHttpRequest(method: string): RequestTrack; setDomainSources(sources: DomainSources): void; close(): void; }; } export const guardedWith = ( onError: (source: string) => void, ): Metrics.Instance["guarded"] => { return (source, fn) => { const report = (error: unknown): void => { logger.error( { source, err: serializeError(error) }, "background loop error", ); onError(source); }; return () => { try { const result = fn(); if (result instanceof Promise) result.catch(report); } catch (error) { report(error); } }; }; }; export const noopMetrics: Metrics.Instance = { forwardsTotal: { inc: () => {} }, forwardFailuresTotal: { inc: () => {} }, takeoversTotal: { inc: () => {} }, degradedHeartbeatsTotal: { inc: () => {} }, registerRejectionsTotal: { inc: () => {} }, dataPlaneConnections: { inc: () => {}, dec: () => {} }, internalError: () => {}, guarded: guardedWith(() => {}), trackHttpRequest: () => ({ route: "unknown", done: () => {} }), setDomainSources: () => {}, close: () => {}, }; const REGISTRY_ROUTES = new Set([ "/registry/workers", "/registry/overview", "/registry/stats", "/registry/health", "/registry/register", "/registry/heartbeat", "/registry/release", "/registry/deregister", "/registry/wind_down", "/registry/drain", "/registry/undrain", ]); export const normalizeRegistryRoute = (pathname: string): string => REGISTRY_ROUTES.has(pathname) ? pathname : "unknown";