Watchlog DocsWatchlog Docs
Home
Get Started
Gen AI Monitoring
Integrations
Log Watchlist
Home
Get Started
Gen AI Monitoring
Integrations
Log Watchlist
  • All Integrations
  • NGINX

    • Nginx Integration
    • Connect NGINX to Watchlog
    • Docker
    • Windows
    • Kubernetes
    • Source Code
  • IIS

    • IIS Integration
    • Ubuntu
    • Docker Container
    • Windows
    • Kubernetes
    • Source Code
  • REDIS

    • Redis Integration
    • Ubuntu
    • Docker Container
    • Windows
    • Kubernetes
    • Source Code
  • POSTGRESQL

    • PostgreSQL Integration
    • Ubuntu
    • Docker Container
    • Windows
    • Kubernetes
    • Source Code
  • MONGODB

    • MongoDB Integration
    • Ubuntu
    • Docker Container
    • Windows
    • Kubernetes
    • Source Code
  • MYSQL

    • MySQL Integration
    • Ubuntu
    • Docker Container
    • Windows
    • Kubernetes
    • Source Code
  • PM2

    • PM2 Integration
    • Ubuntu
    • Docker Container
    • Windows
    • Kubernetes
    • Source Code
  • DOCKER

    • Docker Integration
    • Ubuntu
    • Docker Container
    • Windows
    • Kubernetes
    • Source Code
  • GITLAB

    • Gitlab Integration
    • Ubuntu
    • Docker
    • Windows
    • Kubernetes
    • Source
  • ELASTICSEARCH

    • Elasticsearch Integration
    • Ubuntu
    • Docker Container
    • Windows
    • Kubernetes
    • Source Code

PostgreSQL Integration

Monitor PostgreSQL connections, query performance, cache behaviour, lock contention, table bloat, autovacuum, WAL and checkpoint activity, and replication health from a single Watchlog agent.

Supported Platforms

  • Ubuntu
  • Windows
  • Source Code
  • Docker Container
  • Kubernetes

Supported Versions

PostgreSQL 9.6 through 18. Version differences are detected, not assumed — the agent builds its projection per server version and aliases everything to one stable shape, so no parser branches on version.

The boundaries that matter:

VersionWhat changes
9.6wait_event becomes available
10pg_blocking_pids(), backend_type, interval-typed replication lag
13total_time → total_exec_time, plus planning columns
14pg_stat_wal appears — the WAL tab needs this
15temp_blk_read_time / temp_blk_write_time
16blk_read_time → shared_blk_read_time
17pg_stat_checkpointer splits out of pg_stat_bgwriter
18wal_write / wal_sync removed

Tips

server_version_num is MMmmpp before 10 (90603 = 9.6.3) and MMpppp after (150004 = 15.4). Watchlog compares the raw number — a derived "major" would rank 9.6 above 15.

Required Privileges

From PostgreSQL 10 onward, the built-in pg_monitor role covers everything:

CREATE USER watchlog_monitor WITH PASSWORD 'your_password';
GRANT pg_monitor TO watchlog_monitor;

On 9.6, grant the underlying roles instead:

GRANT pg_read_all_stats TO watchlog_monitor;

For per-table and per-index detail the user also needs CONNECT on each database you want covered — those views only ever describe the database you are connected to:

GRANT CONNECT ON DATABASE myapp TO watchlog_monitor;

A database the user cannot reach simply does not appear. It never breaks the rest.

ViewEnablesWithout it
pg_stat_database, pg_stat_activityConnections, transactions, cache ratioThe integration cannot report
pg_stat_statementsQuery performanceQueries and Slow Queries tabs hidden
pg_locksLock waits and blocking pairsLocks tab hidden
pg_stat_user_tables / _indexesTable and index detail, vacuumTables, Indexes and Vacuum tabs hidden
pg_stat_wal (14+)WAL throughputWAL section hidden
pg_stat_replicationReplica lagReplication tab hidden

pg_stat_statements

Query-level analysis needs the pg_stat_statements extension. It is not installed by default, and Watchlog will never install it — creating an extension changes your database, and that is your decision.

-- postgresql.conf, then restart
shared_preload_libraries = 'pg_stat_statements'
-- once, per database
CREATE EXTENSION pg_stat_statements;

Installed is not the same as readable: the role still needs SELECT, and without pg_read_all_stats it sees <insufficient privilege> instead of the query text. pg_monitor covers both.

When the extension is absent, the Queries and Slow Queries tabs are hidden and a capability note explains why — rather than showing two empty tabs.

What Watchlog Collects

Connections and activity Total, active, idle and idle-in-transaction sessions against max_connections, waiting sessions, longest running query, longest open transaction, and longest idle-in-transaction — the one that quietly holds back vacuum cluster-wide.

Watchlog excludes its own backend from every connection count, so it never reports itself.

Databases Per database: commits and rollbacks with rollback ratio, blocks hit against blocks read, interval cache hit ratio, rows returned / fetched / inserted / updated / deleted, temp files and bytes, deadlocks, conflicts, and database size.

Queries (needs pg_stat_statements) Per statement: calls, total and mean execution time, rows, shared blocks hit and read, temp blocks, WAL bytes, and planning time where available — ranked by impact (calls in the interval × interval mean duration), which is the database time actually consumed.

Locks Lock counts by mode, waiting versus granted, and blocking pairs with both statements.

Tables Live and dead tuples with dead-tuple ratio, sequential versus index scans, rows inserted / updated / deleted / HOT-updated, total, data and index size, heap and index cache hit ratios, and last vacuum / autovacuum timestamps.

Indexes Scans, tuples read and fetched, size, and blocks hit/read, with unused candidates flagged. Primary key, unique and constraint-backed indexes are never removal candidates — they enforce correctness, not performance.

Vacuum Tables needing attention, total dead tuples, tables never vacuumed, vacuums in progress, and whether autovacuum is enabled at all.

WAL and checkpoints WAL records, bytes and full-page images per interval; checkpoints timed versus requested; buffers written by the checkpointer versus by backends.

Replication Per replica: write, flush and replay lag, WAL lag in bytes, state and sync state. On a replica, its own replay position and lag.

Health Score and Insights

A 0–100 score computed server-side, with a written reason on every deduction. Several signals are deliberately context-sensitive, because the naive versions are wrong often enough to be useless:

  • A sequential scan is not a defect. PostgreSQL correctly prefers a scan on a small table. Only a large table where scans outnumber index lookups is flagged.
  • A high dead-tuple ratio on 30 rows is noise. Both a ratio and an absolute count are required.
  • A low cache hit ratio over 200 block accesses means nothing. Volume is required before the score judges — and an analytics workload legitimately reads from disk.
  • An old replay timestamp on an idle primary is not lag. The byte gap is the honest signal.
  • A long query may be a legitimate report. A long transaction is different — it pins the snapshot and blocks vacuum from reclaiming anything it might still see.
  • Rollbacks are an application signal, not a server fault, and are worded neutrally.

Cache hit ratio is computed over the interval, not since the last stats reset. A database up for months reports a lifetime ratio that cannot move; the interval ratio is what reveals a working set falling out of shared_buffers.

Slow Queries

There is no log file to configure. Watchlog reads pg_stat_statements, so query shapes, timings and IO are available as soon as the extension is installed.

slowQuery.thresholdMs (default 100) decides what the dashboard calls slow. The agent, the API and the UI all use that one number so they cannot disagree.

Query text is already normalized by PostgreSQL — literals are $1, $2. Parameter values never leave your host.

Utility statements are the hole

SET, CREATE ROLE … PASSWORD, ALTER USER, CREATE SUBSCRIPTION and COPY are stored verbatim by pg_stat_statements, not normalized. Watchlog scrubs those in full rather than trusting the normalized path, so a password in a CREATE ROLE never reaches storage.

Collection Intervals

SectionInterval
Connections, databases, queries, locks, activity, WAL, checkpoints, replicationevery collection cycle (60s)
Table statistics and sizes300s
Index statistics300s

Per-database views describe only the connected database, so each configured database needs its own connection — which is why storage is throttled well below the 60s tick.

Safety

Watchlog is read-only. It never runs any of the following:

CREATE EXTENSION · ALTER SYSTEM · SET · VACUUM / VACUUM FULL · ANALYZE · REINDEX · CLUSTER · pg_stat_statements_reset() · pg_cancel_backend() · pg_terminate_backend() · any write to any table

Every monitoring statement carries a statement_timeout, so it can never be the thing that hangs a busy server. Index advice is advisory only — no "Drop Index" action is ever offered.

Advanced Options

{
  "service": "postgresql",
  "monitor": true,
  "host": "localhost",
  "port": "5432",
  "username": "watchlog_monitor",
  "password": "your_password",
  "database": ["myapp", "analytics"],
  "ssl": false,

  "advanced": {
    "enabled": true,
    "queries": true,
    "activity": true,
    "locks": true,
    "storage": true,
    "indexes": true,
    "vacuum": true,
    "wal": true,
    "replication": true,
    "maxStatements": 200,
    "maxTables": 300,
    "maxIndexes": 500,
    "maxActivity": 100,
    "maxBlocking": 50,
    "storageIntervalSeconds": 300
  },

  "slowQuery": {
    "thresholdMs": 100
  },

  "activity": {
    "longQuerySeconds": 30,
    "longTransactionSeconds": 60,
    "idleTransactionSeconds": 300
  }
}
FieldDefaultPurpose
database[]Databases to collect per-table and per-index detail for. Cluster-wide metrics need no list.
sslfalseTLS to the server
advanced.maxStatements200Query shapes per scrape, ranked by impact
activity.longQuerySeconds30When a running query counts as long
activity.longTransactionSeconds60When an open transaction counts as long
activity.idleTransactionSeconds300When idle-in-transaction becomes a finding

The activity thresholds are the ones worth tuning to your workload. A reporting database with five-minute queries should raise longQuerySeconds; a pure OLTP database should lower it.

Multiple Instances

Add one entry per instance. Each is identified by its host:port:

[
  {
    "service": "postgresql",
    "monitor": true,
    "host": "127.0.0.1",
    "port": "5432",
    "username": "watchlog_monitor",
    "password": "your_password",
    "database": ["myapp"]
  },
  {
    "service": "postgresql",
    "monitor": true,
    "host": "127.0.0.1",
    "port": "5433",
    "username": "watchlog_monitor",
    "password": "your_password",
    "database": ["analytics"]
  }
]

Troubleshooting

SymptomCause
Queries and Slow Queries tabs missingpg_stat_statements is not installed, or the role cannot read it
Query text shows <insufficient privilege>The role lacks pg_read_all_stats. Grant pg_monitor.
WAL section missingpg_stat_wal requires PostgreSQL 14+
A database is missing from the listThe monitoring role has no CONNECT on it
Vacuum tab missingThe role cannot read pg_stat_user_tables, or advanced.vacuum is off
Replication tab missingThe server is a standalone with no attached replicas
Table sizes look staleThey refresh every 300s by design
current_setting() returns '1kB'It applies units. Watchlog reads numerics from pg_settings instead — mentioned here because it surprises people comparing values by hand.
Last Updated:: 8/13/26, 12:54 AM
Contributors: mohammad
Next
Ubuntu