Log Levels and Log Format¶
Log format¶
Every line is newline-delimited JSON (one complete JSON object per line of output) written to standard output. Every line carries "instance": N to tell apart the logs from multiple Processors running against the same database.
{"ts":"2026-06-01T12:00:00.123456789Z","level":"info","msg":"pg_relay started","workers":2,"instance":1}
{"ts":"2026-06-01T12:00:01.000234567Z","level":"debug","msg":"ok: order_placed, id: 42","instance":1}
{"ts":"2026-06-01T12:00:01.500123456Z","level":"warn","msg":"retry_scheduled: send_email, id: 43","instance":1}
{"ts":"2026-06-01T12:00:05.800234567Z","level":"error","msg":"error: send_email, id: 44","log_id":1234,"instance":1}
The payload is never logged — only correlation identifiers appear (the channel name, the queue ID, the log ID). This means you can ship Processor logs to any log aggregation system without any risk of leaking event data.
Log message reference¶
| Message | Level | Visible at default (warn)? | Extra fields |
|---|---|---|---|
pg_relay started |
info | no | workers |
pg_relay stopping |
info | no | — |
pg_relay stopped |
info | no | — |
pg_relay reconnected |
info | no | — |
instance_limit_reached |
error | yes | detail |
preflight_ok |
debug | no | check, detail |
preflight_warn |
warn | yes | check, detail |
preflight_error |
error | yes | check, detail |
ok: <ch>, id: <id> |
debug | no | — |
skipped: id: <id> |
debug | no | — |
expired: <ch>, id: <id> |
debug | no | — |
invalid: <ch>, id: <id> |
warn | yes | — |
retry_scheduled: <ch>, id: <id> |
warn | yes | — |
error: <ch>, id: <id> |
error | yes | log_id |
max_retries_error: <ch>, id: <id> |
error | yes | log_id |
post_process_error: <ch>, id: <id> |
error | yes | log_id |
probe_error |
error | yes | error |
pending_ids_error |
error | yes | error |
process_error |
error | yes | error, id |
reconnecting |
warn | yes | attempt, backoff_ms, error |
pg_relay paused / pg_relay resumed |
info | no | — (logged once per transition) |
pg_relay reloading / pg_relay reloaded |
info | no | — |
reload_failed |
error | yes | error (the Processor then exits with a non-zero status) |
reload_requested: <ch>, id: <id> |
info | no | — (this instance processed a pg_relay.reload event) |
notifier_detected |
info | no | detail (the registry re-check found the notifier newly installed) |
notifier_unavailable |
warn | yes | detail (why 'notify' events cannot currently be served) |
notifier_interface_unavailable |
warn | yes | registered_version, error |
notify_withheld: id: <id> |
debug | no | — (left unclaimed, pending a registry re-check) |
set_status_failed |
warn | yes | pk, status, error (the event still resolves) |
debug_trace_unavailable / debug_trace_failed |
debug | no | error (tracing never affects the actual send) |
outage_alert_fired |
warn | yes | transport, plus http_status for webhook (the out-of-band outage alert was delivered) |
outage_alert_recovered |
warn | yes | transport, plus http_status for webhook (the recovery message was delivered; the episode resets) |
outage_alert_failed |
warn | yes | kind (outage/recovery), transport, plus http_status or error — the error text never contains the endpoint URL |
start_notify_sent / stop_notify_sent |
info | no | transport, plus http_status for webhook (the lifecycle notification was delivered) |
start_notify_failed / stop_notify_failed |
warn | yes | transport, plus http_status or error (one attempt, best-effort; the Processor runs on / exits regardless) |
notify_config_invalid |
error | yes | error (a lifecycle-notification contract is present but invalid; the Processor then refuses to start) |
spool_config_invalid |
error | yes | error (a PG_RELAY_SPOOL_* size cap is present but not an integer; the Processor then refuses to start) |
spool_dir_unavailable |
warn | yes | variable, path, error (at start: a directory named in the environment does not exist; its channel's events are withheld until it does) |
spool_unavailable / spool_available |
warn / info | yes / no | channel, plus reason for unavailable (a file_spool channel's directory is not configured, missing, unwritable, or at its cap — logged once per transition; events are withheld, not failed) |
spool_withheld: id: <id> |
debug | no | — (one file_spool event left pending because its directory is unavailable) |
spool_exists: <ch>, id: <id> / spool_replaced: <ch>, id: <id> |
info | no | log_id (the file already existed: skipped as a redelivery, or overwritten under replace) |
Continue to High Availability for how to run more than one Processor safely.