Topic 15.1
Database Observability: Metrics, Logs and Traces
In one line
Watch four layers: workload (QPS, latency percentiles, errors per query shape), resources (CPU, memory, disk space, IOPS, throughput), database internals (connections and pool saturation, cache hit ratio, locks and deadlocks, replication lag, vacuum and xid age, checkpoints), and correlation (slow-query logs, plans, and traces linking requests to queries).
Think of it like this
A car dashboard. Speed and fuel (workload and capacity), engine temperature and oil pressure (internals), and warning lights (alerts). Watching only the speedometer won't tell you the engine is about to seize.
Key ideas
- 01
Workload:
pg_stat_statementsfor calls, total and mean time and rows per query shape; application-side p50/p95/p99 per endpoint and query; error rates by SQLSTATE (40001 serialization, 40P01 deadlock, 53300 too many connections, 57014 statement timeout). - 02
Resources: CPU (steal time on cloud VMs), memory and swap, disk free space (alert early: a full disk stops writes), IOPS and throughput versus provisioned limits (cloud volumes throttle silently), network.
- 03
Internals: active and idle-in-transaction connections vs max; pool pending threads; buffer cache hit ratio; lock waits (
pg_locksnot granted), deadlocks (pg_stat_database.deadlocks); replication lag in bytes and seconds; dead tuples and last autovacuum per table;age(datfrozenxid); checkpoint frequency and WAL generation rate; temp file usage. - 04
Logs:
log_min_duration_statement,log_lock_waits,log_temp_files,log_autovacuum_min_duration,auto_explainfor slow plans; connection failures and replication errors. - 05
Tracing: OpenTelemetry JDBC instrumentation creates a span per query with the statement shape; add
application_nameand a SQL comment with the trace ID (sqlcommenter) so a slow query in the database log leads back to the exact request and service.
Code & diagrams
-- connections by state
SELECT state, count(*) FROM pg_stat_activity GROUP BY state;
-- long transactions (block vacuum, hold locks)
SELECT pid, now() - xact_start AS age, state, left(query, 60)
FROM pg_stat_activity WHERE xact_start < now() - interval '5 minutes' ORDER BY age DESC;
-- lock waits right now
SELECT a.pid, a.wait_event_type, a.wait_event, pg_blocking_pids(a.pid), left(a.query, 60)
FROM pg_stat_activity a WHERE a.wait_event_type = 'Lock';
-- per-database health
SELECT datname, xact_commit, xact_rollback, deadlocks, temp_bytes,
round(100.0 * blks_hit / nullif(blks_hit + blks_read, 0), 2) AS hit_pct
FROM pg_stat_database WHERE datname NOT LIKE 'template%';groups:
- name: postgres
rules:
- alert: PostgresReplicationLagHigh
expr: pg_replication_lag_seconds > 30
for: 2m
- alert: PostgresDiskSpaceLow
expr: node_filesystem_avail_bytes{mountpoint="/var/lib/postgresql"} / node_filesystem_size_bytes < 0.15
for: 5m
- alert: PostgresConnectionsNearMax
expr: sum(pg_stat_activity_count) / pg_settings_max_connections > 0.8
for: 5m
- alert: PostgresXidAgeHigh
expr: max(pg_database_age) > 1000000000 # well before wraparound trouble
- alert: PostgresLongTransaction
expr: pg_stat_activity_max_tx_duration > 600Interview problem
The problem
Build the on-call dashboard for a critical database
Design the single dashboard and the alert set an on-call engineer uses for the orders database. Explain what each panel detects.
When it breaks
Alerting on CPU only
What you see
The database is fine on CPU while IOPS are throttled at the volume limit and latency triples; nobody is paged until customers complain.
Fix & prevent
Alert on user-facing latency and errors, and on IOPS and throughput versus provisioned limits.
Explain it without notes
Which database metrics predict an outage before users notice?
Practice
Add trace correlation so a slow query in logs can be traced to its request.
Trade-offs
- ↔
More telemetry means more cost and noise; focus on symptoms and leading indicators with runbooks.
Done when you can
I can define the metrics, logs, traces and alerts for a production database.