Skip to content

feat: add transaction ID age to postgres_exporter - #2375

Draft
valigula wants to merge 2 commits into
developfrom
andres/INDATA-1261-add-max-transaction-id-age-metric
Draft

feat: add transaction ID age to postgres_exporter#2375
valigula wants to merge 2 commits into
developfrom
andres/INDATA-1261-add-max-transaction-id-age-metric

Conversation

@valigula

@valigula valigula commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

What kind of change does this PR introduce?

feature INDATA-1261

What is the current behavior?

What is the new behavior?

Add pg_wraparound custom metric to postgres_exporter that tracks the maximum transaction ID age across all databases. This enables proactive monitoring of wraparound risk before it reaches critical thresholds.

  • New queries.yml with max(age(datfrozenxid)) query
  • Deployed to /opt/postgres_exporter/ via Ansible

Additional context

Test

Copying/creating the file in local-dev, setting the permissions

root@db-hkcvznjogvigukdmrznn:/opt/postgres_exporter# touch /tmp/queries.yml
root@db-hkcvznjogvigukdmrznn:/opt/postgres_exporter# vi /tmp/queries.yml
root@db-hkcvznjogvigukdmrznn:/opt/postgres_exporter# cp /tmp/queries.yml /opt/postgres_exporter/queries.yml
root@db-hkcvznjogvigukdmrznn:/opt/postgres_exporter# chown root:root /opt/postgres_exporter/queries.yml
root@db-hkcvznjogvigukdmrznn:/opt/postgres_exporter# chmod 0644 /opt/postgres_exporter/queries.yml
root@db-hkcvznjogvigukdmrznn:/opt/postgres_exporter# ls -la /opt/postgres_exporter/queries.yml
-rw-r--r-- 1 root root 265 Aug 21 15:29 /opt/postgres_exporter/queries.yml

restarting postgres_exported

root@db-hkcvznjogvigukdmrznn:/opt/postgres_exporter#  systemctl restart postgres_exporter
root@db-hkcvznjogvigukdmrznn:/opt/postgres_exporter# journalctl -u postgres_exporter -n 30 --no-pager
Aug 21 10:20:52 db-hkcvznjogvigukdmrznn postgres_exporter[620]: ts=2026-08-21T10:20:52.593Z caller=postgres_exporter.go:682 level=error err="Error opening connection to database (host=localhost%20dbname=postgres%20sslmode=disable%20user=supabase_admin%20pg_stat_statements.track=none%20application_name=postgres_exporter): driver: bad connection"
Aug 21 10:21:47 db-hkcvznjogvigukdmrznn postgres_exporter[620]: ts=2026-08-21T10:21:47.635Z caller=server.go:74 level=info msg="Established new database connection" fingerprint=localhost:5432
Aug 21 10:21:47 db-hkcvznjogvigukdmrznn postgres_exporter[620]: ts=2026-08-21T10:21:47.640Z caller=postgres_exporter.go:613 level=info msg="Semantic version changed" server=localhost:5432 from=0.0.0 to=17.6.0
Aug 21 15:21:00 db-hkcvznjogvigukdmrznn systemd[1]: Stopping postgres_exporter.service - Postgres Exporter...
Aug 21 15:21:00 db-hkcvznjogvigukdmrznn systemd[1]: postgres_exporter.service: Deactivated successfully.
Aug 21 15:21:00 db-hkcvznjogvigukdmrznn systemd[1]: Stopped postgres_exporter.service - Postgres Exporter.
Aug 21 15:21:00 db-hkcvznjogvigukdmrznn systemd[1]: postgres_exporter.service: Consumed 1.771s CPU time, 21.4M memory peak, 0B memory swap peak.
-- Boot 1fa8a6e85faf4f039d299003f54d504a --
Aug 21 15:21:14 db-hkcvznjogvigukdmrznn systemd[1]: Started postgres_exporter.service - Postgres Exporter.
Aug 21 15:21:15 db-hkcvznjogvigukdmrznn postgres_exporter[630]: ts=2026-08-21T15:21:15.228Z caller=main.go:86 level=warn msg="Error loading config" err="Error opening config file \"postgres_exporter.yml\": open postgres_exporter.yml: no such file or directory"
Aug 21 15:21:15 db-hkcvznjogvigukdmrznn postgres_exporter[630]: ts=2026-08-21T15:21:15.231Z caller=proc.go:267 msg="Excluded databases" databases=[]
Aug 21 15:21:15 db-hkcvznjogvigukdmrznn postgres_exporter[630]: ts=2026-08-21T15:21:15.231Z caller=main.go:99 level=warn msg="The extended queries.yaml config is DEPRECATED" file=/opt/postgres_exporter/queries.yml
Aug 21 15:21:15 db-hkcvznjogvigukdmrznn postgres_exporter[630]: ts=2026-08-21T15:21:15.236Z caller=tls_config.go:274 level=info msg="Listening on" address=[::]:9187
Aug 21 15:21:15 db-hkcvznjogvigukdmrznn postgres_exporter[630]: ts=2026-08-21T15:21:15.237Z caller=tls_config.go:277 level=info msg="TLS is disabled." http2=false address=[::]:9187
Aug 21 15:21:17 db-hkcvznjogvigukdmrznn postgres_exporter[630]: ts=2026-08-21T15:21:17.518Z caller=server.go:74 level=info msg="Established new database connection" fingerprint=localhost:5432
Aug 21 15:21:17 db-hkcvznjogvigukdmrznn postgres_exporter[630]: ts=2026-08-21T15:21:17.531Z caller=postgres_exporter.go:613 level=info msg="Semantic version changed" server=localhost:5432 from=0.0.0 to=17.6.0
Aug 21 15:29:33 db-hkcvznjogvigukdmrznn systemd[1]: Stopping postgres_exporter.service - Postgres Exporter...
Aug 21 15:29:33 db-hkcvznjogvigukdmrznn systemd[1]: postgres_exporter.service: Deactivated successfully.
Aug 21 15:29:33 db-hkcvznjogvigukdmrznn systemd[1]: Stopped postgres_exporter.service - Postgres Exporter.
Aug 21 15:29:33 db-hkcvznjogvigukdmrznn systemd[1]: Started postgres_exporter.service - Postgres Exporter.
Aug 21 15:29:33 db-hkcvznjogvigukdmrznn postgres_exporter[3208]: ts=2026-08-21T15:29:33.120Z caller=main.go:86 level=warn msg="Error loading config" err="Error opening config file \"postgres_exporter.yml\": open postgres_exporter.yml: no such file or directory"
Aug 21 15:29:33 db-hkcvznjogvigukdmrznn postgres_exporter[3208]: ts=2026-08-21T15:29:33.120Z caller=proc.go:267 msg="Excluded databases" databases=[]
Aug 21 15:29:33 db-hkcvznjogvigukdmrznn postgres_exporter[3208]: ts=2026-08-21T15:29:33.120Z caller=main.go:99 level=warn msg="The extended queries.yaml config is DEPRECATED" file=/opt/postgres_exporter/queries.yml
Aug 21 15:29:33 db-hkcvznjogvigukdmrznn postgres_exporter[3208]: ts=2026-08-21T15:29:33.121Z caller=tls_config.go:274 level=info msg="Listening on" address=[::]:9187
Aug 21 15:29:33 db-hkcvznjogvigukdmrznn postgres_exporter[3208]: ts=2026-08-21T15:29:33.121Z caller=tls_config.go:277 level=info msg="TLS is disabled." http2=false address=[::]:9187

Asserting the results

root@db-hkcvznjogvigukdmrznn:/opt/postgres_exporter# curl -s http://localhost:9187/metrics | grep -i wraparound
# HELP pg_wraparound_max_transaction_id_age Max transaction ID age (in XIDs; wraparound risk) across databases
# TYPE pg_wraparound_max_transaction_id_age gauge
pg_wraparound_max_transaction_id_age{server="localhost:5432"} 1137
root@db-hkcvznjogvigukdmrznn:/opt/postgres_exporter# psql -U supabase_admin -d postgres -c "SELECT max(age(datfrozenxid)) AS max_transaction_id_age FROM pg_database;"
Password for user supabase_admin:
root@db-hkcvznjogvigukdmrznn:/opt/postgres_exporter# psql  -h localhost -U supabase_admin -d postgres -c "SELECT max(age(datfrozenxid)) AS max_transaction_id_age FROM pg_database;"
 max_transaction_id_age
------------------------
                   1137
(1 row)

Add pg_wraparound custom metric to postgres_exporter that tracks the
maximum transaction ID age across all databases. This enables proactive
monitoring of wraparound risk before it reaches critical thresholds.

- New queries.yml with max(age(datfrozenxid)) query
- Deployed to /opt/postgres_exporter/ via Ansible

Related: INDATA-1261
@valigula
valigula requested review from a team as code owners August 18, 2026 12:41
@valigula
valigula requested a lite review from Copilot August 18, 2026 12:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a custom postgres_exporter metric to monitor wraparound risk by exporting the maximum age(datfrozenxid) across all databases, deployed via Ansible.

Changes:

  • Deploy a new queries.yml containing the pg_wraparound custom query/metric definition.
  • Copy queries.yml into /opt/postgres_exporter/ during exporter provisioning.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
ansible/tasks/internal/postgres-exporter.yml Copies the new custom queries.yml into the exporter install directory during provisioning.
ansible/files/queries.yml Defines the pg_wraparound extended query exporting max transaction ID age across databases.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +44 to +48
src: files/queries.yml
dest: /opt/postgres_exporter/queries.yml
owner: root
group: root
mode: '0644'
Comment thread ansible/files/queries.yml Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@valigula
valigula marked this pull request as draft August 21, 2026 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants