Observability Overview
Deserve emits lifecycle and error events through a built-in event bus. A single router.on() subscription receives every event, which keeps logging, metrics, and error reporting in one place instead of scattering console.log calls across handlers.
This middleware-style hook sits beside the router and watches everything that happens, from server startup to each finished request.

Subscribing to Events
router.on() registers a listener and returns an unsubscribe function:
import { Router } from '@neabyte/deserve'
const router = new Router({
routes: { directory: './routes' }
})
// Receive every lifecycle and error event
const off = router.on((event) => {
console.log(event.kind, event.metadata)
})
await router.serve(8000)
// Stop listening later
off()The listener fires for all event kinds, so filtering happens inside the callback. With no listener registered, emitting is a no-op and costs nothing, so the bus stays free until something subscribes.
Event Shape
Every event shares the same envelope:
{
type: 'internal' | 'external', // origin channel
kind: string, // event name, such as 'request:completed'
metadata: { ... }, // fields specific to the kind
timestamp: number // epoch milliseconds
}type-externalfor normal client traffic,internalfor framework faults. A request event isinternalwhen a framework error, the synthetic 503 timeout, or a missing request context produced it, otherwiseexternal. Theprocess:failedkind is the one exception that always staysexternal, since a crashed process sits outside the request channel. Every other kind is alwaysinternal.kind- the discriminant used to tell events apart.metadata- readonly fields that depend on the kind.timestamp- when the event was created.
The full list of kinds and their metadata lives in Event Reference.
Difference From a Domain Event Bus
The observability bus reports framework activity such as requests, routes, views, and faults. A domain event bus carries application facts like user:created. They serve different jobs and often run side by side. See the domain event bus pattern for sharing application events across services.
A Built-In Audit Trail
Every subsystem reports on the same bus, from server and route signals to worker, security middleware, and process faults. Each one arrives as the same { type, kind, metadata, timestamp } envelope, structured and stamped at the instant it fires. A plain listener becomes an audit trail that records itself as the server runs, with no extra wiring.
That covers what compliance and security work usually ask for, and each control maps to a behaviour the bus already provides:
- SOC 2 (CC7 monitoring) wants security-relevant events captured. Tampered cookies (
session:invalid), blocked termination calls (process:failed), and failed CSRF rules (csrf:failed) all emit on their own. - ISO/IEC 27001 (A.8.15 logging) wants an event log that holds up over time. Every event carries a
timestampin epoch milliseconds and arrives in order, so a timeline reconstructs cleanly. - PCI DSS (Requirement 10 audit trails) wants each action tied to its source.
request:completedreportsmethod,url,statusCode,durationMs, and an optionalipwhen the address is known. - SIEM and real-time alerting want a feed to ingest. A single
router.on()forwards the whole surface to wherever logs or alerts go.
The type field keeps the fault channel clean. Normal client traffic is external, while a framework error, the synthetic 503 timeout, or a missing request context marks the event internal. A fault alert pipeline filters on internal to catch framework faults without drowning in routine requests, then folds in process:failed by kind, since a process fault always rides the external channel:
router.on((event) => {
// Forward framework and process faults
if (event.type === 'internal' || event.kind === 'process:failed') {
console.log(JSON.stringify({ at: event.timestamp, ...event }))
}
})Where to Go Next
- Event Reference - every event kind and its metadata.
- Request Logging - turn events into a structured access log.
- Error Reporting - record failures and pair with error handling.