Midwess
Operate

PgPaw writes operational logs to stderr. Logs use logfmt-style fields and are emitted at INFO, WARN, and ERROR. You do not need debug logs to know that PgPaw is working.

Example:

ts=2026-06-29T10:00:08.120Z level=INFO pid=65538 target=pgpaw::http::server event=http_server_listening bind_addr=127.0.0.1:8080 url=http://127.0.0.1:8080

Startup logs

During pgpaw serve, expect to see:

level=INFO target=pgpaw event=command_start command=serve
level=INFO target=pgpaw event=server_starting bind_addr=127.0.0.1:8080 data_dir="./pgpaw-data" upstream_host=127.0.0.1 upstream_port=5432 upstream_database=myapp publication=pgpaw_pub slot=pgpaw_slot sslmode=disable auth_configured=false cors_origin=None
level=INFO target=pgpaw::di event=preflight_start upstream_host=127.0.0.1 upstream_port=5432 upstream_database=myapp publication=pgpaw_pub
level=INFO target=pgpaw::di event=schema_scan_complete tables=4 primary_key_tables=4 replica_identity_full_tables=0
level=INFO target=pgpaw::http::server event=http_server_listening bind_addr=127.0.0.1:8080 url=http://127.0.0.1:8080
level=INFO target=pgpaw event=server_ready bind_addr=127.0.0.1:8080 health_path=/healthz query_path=/query

The most important line is event=http_server_listening. It includes the port and full local URL.

Request logs

Every HTTP request is logged through Actix middleware:

level=INFO target=actix_web::middleware::logger event=http_request remote_addr=127.0.0.1 request="POST /query HTTP/1.1" status=303 response_bytes=0 duration_ms=2 user_agent="curl/8.7.1"

Query logs

PgPaw logs query decisions without logging raw SQL:

level=INFO target=pgpaw::http::query event=query_classified fingerprint=9a4f tables=users live=false scope=public
level=INFO target=pgpaw::cache event=query_cache_get_or_compute result=hit key=9a4f:42 bytes=128
level=INFO target=pgpaw::http::query event=query_snapshot scope=public fingerprint=9a4f tables=users version=42 cursor=/q/9a4f/42 response=redirect snapshot_bytes=128

For private requests:

level=INFO target=pgpaw::auth event=auth_header_present
level=INFO target=pgpaw::auth event=auth_verified role=member
level=INFO target=pgpaw::http::query event=query_snapshot scope=private fingerprint=9a4f tables=documents version=42 role=member response=inline snapshot_bytes=512

CDC and live logs

level=INFO target=pgpaw::cdc event=cdc_transaction txid=124 lsn=12345678 changes=1
level=INFO target=pgpaw::live event=live_commit txid=124 lsn=12345678 changed_tables=orders subscriptions_matched=2
level=INFO target=pgpaw::live event=live_diff subscription_id=12 txid=124 previous_rows=3 next_rows=3 deltas=1

If live subscriptions fall behind:

level=WARN target=pgpaw::live event=live_reset subscriptions=4 reason=broadcast_lag

Clients should reconnect and request a fresh snapshot after a reset.

Warnings and errors

Important warning/error events include:

Event Meaning
init_complete result=restart_required Restart Postgres before serve.
init_setting_manual_required Apply the printed WAL setting manually.
http_server_bind_failed The configured host/port could not be bound.
auth_failed Token is malformed, invalid, expired, or verifier is missing.
cursor_miss Snapshot cursor is unknown or evicted.
health_check status=halted Replica is halted; /healthz returns 503.
http_error status=503 Request failed because the replica is halted.

Sensitive data policy

PgPaw does not log:

  • raw bearer tokens;
  • Postgres passwords;
  • raw SQL text.

Logs use SQL fingerprints, table names, roles, versions, cursor paths, and byte counts instead. This keeps logs useful for operators without exposing query literals or credentials.

Capture logs

Shell:

pgpaw serve ... 2>&1 | tee pgpaw.log

systemd:

journalctl -u pgpaw -f

Docker:

docker logs -f <container>