Observability@rhythmjs/observability
API reference
Exports and signatures for the log, request-id, and timing subpaths of @rhythmjs/observability.
On this page
@rhythmjs/observability/log#
function log(sink?: LogSink): Middleware<RhythmHttpContext>;Returns middleware that measures each request and calls the sink once per request. Without an argument, the default sink prints METHOD /path status Nms to the console. When downstream throws, the sink receives an entry with status: 500 and the error, then the error is rethrown so an outer exception filter still sees it.
LogEntry#- The structured entry passed to the sink:
method: string,path: string,status: number,duration: number(rounded milliseconds), anderror?: unknown, set only when downstream threw. LogSink#(entry: LogEntry) => void | Promise<void>. Sync or async; an async sink is awaited before the middleware returns.
@rhythmjs/observability/request-id#
function requestId(header?: string): Middleware<RhythmHttpContext>;Returns middleware that reads the incoming header named by header (default "x-request-id") and reuses its value, or generates a new id with crypto.randomUUID(). The id is set on the response under the same header name and passed downstream as ctx.requestId.
RequestIdContext#{ requestId: string }. The context extension made available to downstream middleware; use it as the type argument ofuseso handlers seectx.requestId.
@rhythmjs/observability/timing#
function timing(name?: string): Middleware<RhythmHttpContext>;Returns middleware that appends a Server-Timing header after next() resolves, in the form name;dur=N with the downstream duration in milliseconds to one decimal place, measured with Bun's native Bun.nanoseconds(). The metric name defaults to "app". The header is appended, not replaced, so multiple timing() layers each contribute their own metric.
@rhythmjs/observability/health#
function createHealthService(options?: HealthModuleOptions): HealthService
const healthModule: { forRoot(options?): Rhythm } // context: { healthService }
function healthRoutes(service: HealthService, options?: { path?: string }): RhythmRouter
function gracefulShutdown(options?: GracefulShutdownOptions): () => Promise<void>HealthIndicator#{ name, check(): HealthResult, critical?, timeout? }.criticaldefaults to true; a down critical indicator makes the whole report down; non-critical failures are reported but do not. Each check races its owntimeout(falling back to the module-leveltimeout, default 5000ms) and a throw or timeout counts as down with the error indetails.HealthService#live()-{ status: "up", uptime, timestamp }, no indicators involved.ready()returns aHealthReport(status,shuttingDown, per-indicatorcheckswith durations), cached forcacheTtl(default 1000ms).shutdown()flipsisShuttingDownand makesready()report down immediately.healthRoutes(service, { path? })#- A router (default prefix
/health) servingGET /live(always 200) andGET /ready(200 up, 503 down). GracefulShutdownOptions#healthService(flipped first),closehook (runs after the drain; release your own resources here),signals(defaultSIGTERM/SIGINT),drainMs(default 0),timeoutMs(hard cap, default 10 000), andexit. Returns the shutdown function so you can also invoke it directly.