rhythmjs

Search documentation

Search guides, the tutorial and every package.

On this page

@rhythmjs/observability/log#

TypeScript
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), and error?: 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#

TypeScript
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 of use so handlers see ctx.requestId.

@rhythmjs/observability/timing#

TypeScript
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#

TypeScript
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? }. critical defaults to true; a down critical indicator makes the whole report down; non-critical failures are reported but do not. Each check races its own timeout (falling back to the module-level timeout, default 5000ms) and a throw or timeout counts as down with the error in details.
HealthService#
live() - { status: "up", uptime, timestamp }, no indicators involved. ready() returns a HealthReport (status, shuttingDown, per-indicator checks with durations), cached for cacheTtl (default 1000ms). shutdown() flips isShuttingDown and makes ready() report down immediately.
healthRoutes(service, { path? })#
A router (default prefix /health) serving GET /live (always 200) and GET /ready (200 up, 503 down).
GracefulShutdownOptions#
healthService (flipped first), close hook (runs after the drain; release your own resources here), signals (default SIGTERM/SIGINT), drainMs (default 0), timeoutMs (hard cap, default 10 000), and exit. Returns the shutdown function so you can also invoke it directly.