Observability
The server ships a structured-logger port that every adapter uses to emit
JSON log lines carrying a per-request traceId and per-connection
connectionId. The canonical event names are the contract dashboards and
log queries are built against.
Log contract
Every record is one physical line of JSON with at least:
| Field | Source |
|---|---|
ts |
ISO-8601 timestamp from the injected Clock. |
level |
debug / info / warn / error. |
msg |
Event name (see below). |
traceId |
Per-request id; fresh per inbound frame. |
connectionId |
The bound connection's id (ConnId). |
Additional structured fields appear per event. The msg catalogue:
msg |
Level | Emitted by | Notes |
|---|---|---|---|
frame.receive |
debug | ConnectionActor |
One per parsed IRC line. Fields: command, lines. |
frame.parse-error |
warn | ConnectionActor |
A line failed to parse. Fields: line, token. |
dispatch |
debug | dispatch() |
Before interpreting an effect list. Fields: effects (array of tags), histogram. |
dispatch.error |
warn | dispatch() |
A runtime method rejected. Fields: effect, err. |
Adapters may emit their own events (e.g. local-cli listening, shutdown)
following the same shape.
Cloudflare Workers
The apps/cf-worker/wrangler.toml enables [observability] so every
console.* line emitted by the ConsoleLogger inside ConnectionDO is
captured by Workers Analytics.
- Tail the live feed:
pnpm --filter @serverless-ircd/cf-worker tail - Filter by connection:
connectionId = "<DO hex id>" - Filter by trace:
traceId = "<uuid>" - Errors only:
level = "error" or msg = "dispatch.error"
Workers Analytics dashboards can be built on the Cloudflare dashboard under Workers & Pages → → Observability.
AWS (Lambda + API Gateway WebSocket)
The Lambda handler writes to CloudWatch Logs via the global console.
Each invocation emits one JSON line per log record; the log group name
follows the standard /aws/lambda/<function-name> convention.
A starter CloudWatch dashboard is checked in at
dashboards/cloudwatch-irc.json. Provision it via:
aws cloudwatch put-dashboard \
--dashboard-name ServerlessIRCd-staging \
--dashboard-body file://dashboards/cloudwatch-irc.json
The dashboard variables (API_ID, LAMBDA_NAME, LOG_GROUP_ARN,
AWS_REGION) are templated by CloudWatch's dashboard variables feature —
set them once in the dashboard UI after import.
Sample CloudWatch Logs Insights query — count dispatched effects by tag over the last hour:
fields @timestamp, msg, fields.histogram
| filter msg = "dispatch"
| sort @timestamp desc
Local CLI
The local-cli server uses the same ConsoleLogger so the structured
stream is visible while developing:
{"ts":"2026-07-22T12:34:56.789Z","level":"debug","msg":"frame.receive","traceId":"…","connectionId":"…","command":"PRIVMSG","lines":1}
Filter with jq:
pnpm --filter local-cli start | jq 'select(.msg=="dispatch.error")'