PostgreSQL Database Monitoring
Collect PostgreSQL health metrics and query-performance traces without running a separate exporter
groundcover connects directly to a PostgreSQL instance to collect built-in health metrics and query statistics without requiring a separate Prometheus exporter. You can use the health metrics in dashboards and monitors and inspect query statistics as traces.
Prerequisites
The integration must run from a groundcover backend or monitored cluster that can reach the PostgreSQL host and port.
Create a dedicated monitoring user, grant access to PostgreSQL statistics views, and enable pg_stat_statements in every database from which you want to collect query statistics:
CREATE USER groundcover WITH PASSWORD '<password>';
GRANT pg_monitor TO groundcover;
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;As a database administrator, check the active preload value and whether the server has detected a change that requires a restart:
SELECT name, setting AS active_value, pending_restart, source, sourcefile, sourceline
FROM pg_settings
WHERE name = 'shared_preload_libraries';active_value is the running server's value. pending_restart = true means the server has reread a changed setting that needs a restart; it does not show the replacement value. Changes in files that the server has not reread may not be reflected in this flag.
To inspect the current configuration-file values, including entries that override earlier ones, run:
SELECT sourcefile, sourceline, seqno, setting AS configured_value, applied, error
FROM pg_file_settings
WHERE name = 'shared_preload_libraries'
ORDER BY seqno;Review the entries in order and check error; applied = false can indicate an overridden entry or a setting that cannot take effect yet. This view reads the current files, not the active server state, and requires superuser access by default. If your managed service restricts access, inspect its parameter group or database flags instead. See PostgreSQL's pg_settings and pg_file_settings references.
Preserve every existing entry and append pg_stat_statements to the comma-separated list if it is not already present. For example, a configured value of pgaudit becomes pgaudit,pg_stat_statements. Do not replace an existing list with only pg_stat_statements. After applying the configuration and restarting, rerun the first query to confirm that the active value includes pg_stat_statements and pending_restart is false.
Configure these settings in postgresql.conf:
If you use a managed PostgreSQL service, apply server-level settings through the provider's parameter-group or database-flags interface. Preserve the existing shared_preload_libraries entries there and append pg_stat_statements if it is missing. Apply the change and restart the database as required by your provider. Managed services also expose administrative databases that the monitoring user cannot read; exclude those databases from collection.
What it collects
Built-in health metrics
PostgreSQL engine health and capacity under the groundcover_db_pg_* prefix
Data Explorer, monitors, and the PostgreSQL dashboard from the Dashboard Catalog
Query statistics
Rows from pg_stat_statements, represented as traces with database semantic-convention attributes
pg_stat_statements collection is independent of health-metric collection. Each distinct statement becomes a standalone trace containing calls, execution time, rows, and shared-block statistics; it is not joined to the application trace that issued the query.
See Verify collection for copyable metric queries and trace filters.
Health metric groups
All health groups are enabled by default when built-in health metrics are enabled. You can disable individual groups in the app or configuration.
Connections
Client connections by state (active, idle, idle in transaction, waiting) and the server's max_connections limit.
Available from standard statistics views.
Replication
Replication lag in seconds and bytes per replica, and how much WAL each replication slot is holding back.
Replica and slot series are empty when neither is configured. Some queries apply only to a primary.
Standby
On a replica: how far behind the primary it is, and whether the WAL receiver is still connected.
Collected only when the monitored instance is in recovery.
Database stats
Per-database transactions, cache hit ratio, rows read and written, deadlocks, temp file spills and session totals.
Excluded databases do not produce series.
Transaction wraparound
How much transaction ID headroom each database has left before wraparound forces the server to stop accepting writes.
Excluded databases do not produce series.
Database size
On-disk size of each database.
Excluded databases do not produce series.
Conflicts
Queries cancelled on a standby because WAL replay conflicted with them, broken down by reason.
Normally empty on a primary or when a standby has no recovery conflicts.
WAL archiver
WAL segments successfully archived, and archive failures.
Can remain empty or inactive when archiving is not configured.
Instance
Server uptime, current timeline, and the count, size and age of files in the WAL directory.
Some filesystem-level values require statistics-monitoring privileges.
Locks
Locks held and waiting by lock mode, and how long the oldest idle-in-transaction session has been holding one.
Requires statistics-monitoring privileges; waiting-lock series are empty when there is no contention.
Checkpoints
How often checkpoints run and how long they take, and how many buffers the checkpointer, background writer and backends each wrote.
The exact server counters used are selected automatically from available capabilities.
WAL
WAL records and bytes generated, full-page images written, and time spent writing and syncing WAL.
Collected when the server exposes the required WAL statistics.
I/O
Reads, writes, extends and fsyncs by backend type and context, with timing when track_io_timing is enabled.
Collected when the server exposes the required I/O statistics. Timing values require track_io_timing.
Set it up
Open Data Sources, select PostgreSQL, and complete the wizard:

Prepare PostgreSQL — run the provided user, grant, extension, and server-configuration commands.
Connection — enter a name, host, optional port and database, and TLS settings. The database is the connection database; health metrics are collected for every non-excluded database on the instance.
Cluster scoping — run the integration from the backend or from a monitored cluster that can reach the database.
Authentication — provide the monitoring user's basic-auth credentials and enable TLS under Connection. Select no authentication only when the database is deliberately configured for passwordless access and network controls restrict access to trusted clients, including the integration's execution location. Never expose an unauthenticated database endpoint to the public internet.
Collection — choose query-statistics collection, INSERT filtering, the maximum statements per scrape, the shared scrape interval, and health-metric groups.
Database filtering — list administrative or application databases to exclude. Every other database on the instance is monitored.
Ingestion settings — add labels such as
environmentorteamto every collected metric.
Save the integration, then use Verify collection to confirm both metrics and query traces are arriving.
Use the canonical Terraform examples, selecting the postgresql_dbm resource with type = "postgresqldbm". Follow the provider configuration guide and groundcover_dataintegration reference.
Replace the example endpoint, database, username, and integration name with your values. Configure the execution cluster and password reference as described in Credentials and execution location, then review terraform plan before applying.
Use the canonical PostgreSQL DataIntegration manifest. Follow the provider setup instructions to install the provider and configure its credentials.
Replace the example endpoint, database, username, integration name, and providerConfigRef with your values. Configure the execution cluster and password reference as described in Credentials and execution location, then apply the manifest to the Kubernetes cluster running Crossplane.
Configuration notes
Credentials and execution location
Choose an execution location with network access to the PostgreSQL endpoint:
A cluster-run integration uses the integrations agent in the selected monitored cluster. Use
secretRef::k8s::<namespace>::<secret-name>::<key>to read an existing Kubernetes Secret from that cluster.A backend-run integration uses the integrations agent on the groundcover backend. Store the password through the app or use
secretRef::store::<id>in API-managed configuration.
Create a Kubernetes Secret
For a cluster-run integration, store the monitoring user's database password in a local file using your secret-management workflow. Restrict access to the file and ensure it contains only the password, with no trailing newline. Create the Secret in the cluster selected in Cluster scoping:
The namespace must already exist. This creates a Secret named groundcover-postgresql with a data key named admin-password. Reference it in the integration's authentication.basicAuth.password field:
Replace the context, namespace, Secret name, and key to match your environment. Use the dedicated monitoring username created in Prerequisites.
Backend-run credentials
For a backend-run integration, select Run the integration from the backend and enter the monitoring username and password under Authentication in the app wizard. Saving the integration stores the password as a secret. A secretRef::store::<id> reference identifies a secret in that store; use an existing secret's ID for IaC configuration. Omit cluster for backend execution.
Never put a plaintext production password in Terraform or Crossplane configuration.
TLS
Enable TLS for encrypted database connections. Keep certificate verification enabled whenever the PostgreSQL endpoint presents a certificate trusted by the integration's runtime. Use the skip-verification option only when you understand and accept the risk of an internal or self-signed certificate chain.
Query-statistics options
maxQueries limits each scrape to the statements with the highest cumulative execution time. filterInserts excludes all INSERT statements, which can prevent high-volume writes from crowding other statements out of the result.
Verify collection
Open the integration from Data Sources.
Use Stats to confirm that PostgreSQL metrics are arriving and Activity Traces to inspect collection attempts and errors.
In Data Explorer, query the built-in metrics for this integration:
Install the PostgreSQL dashboard from the Dashboard Catalog and select the integration or server endpoint.
In Traces, choose a time range covering recent database activity. Filter by
gc_integration_nameusing the Name you entered in the wizard (orconfig.namein IaC), and bysource.tableto find the collected database statements:Open a matching trace to inspect its SQL statement and database statistics. These are the collected query-statistics traces; Activity Traces in the data-source drawer show the integration's collection attempts.
Troubleshooting
The integration cannot connect
Confirm that the selected execution location can resolve and reach the host and port. Then verify the username, secret reference, TLS mode, and certificate trust. Use the most recent Activity Traces entry to inspect reported network, authentication, and query failures.
Health metrics are missing
Edit the integration and confirm that Collect health metrics and the expected groups are enabled.
Confirm that the user still has
pg_monitorand can read PostgreSQL statistics views.Check whether the group applies to the server's current capabilities and primary/standby role. Replication, standby, conflict, lock-wait, and archiver groups can legitimately return no rows.
For I/O timing values, confirm that
track_io_timingis enabled.Check Stats, Activity Traces, and the MetricsQL selector above. The product does not currently expose a persisted per-group status view.
Query traces are missing
Confirm that query-statistics collection is enabled, pg_stat_statements is loaded, and the extension exists in the connection database. Check that statements have executed since statistics were last reset and that INSERT filtering is not excluding the workload you expect.
A database produces permission errors
Add managed-service administrative databases and any intentionally inaccessible databases to Ignored databases. The list is exclusion-based: newly created databases are monitored automatically unless you add them to the list.
For general integration diagnostics, see Monitor Data Sources Integrations.
Related documentation
Last updated
