Add PostgreSQL and Miniflux services to tailnet #16

Merged
eblume merged 15 commits from feature/add-miniflux-postgresql into main 2026-01-16 12:30:21 -08:00
4 changed files with 157 additions and 1 deletions
Showing only changes of commit 7dca29aea9 - Show all commits

Add XID exhaustion tracking to PostgreSQL dashboard

- Add custom query for pg_database XID age monitoring
- Add gauge showing XID age with threshold warnings (yellow at 150M, red at 180M)
- Add time series chart for XID age trends
- URL-encode postgres password in alloy connection string

XID (transaction ID) exhaustion can cause PostgreSQL to shut down to prevent
wraparound. Default autovacuum_freeze_max_age is 200M, so warnings start well
before that threshold.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Erich Blume 2026-01-16 12:15:45 -08:00

View file

@ -50,6 +50,14 @@
# === Deploy configuration ===
- name: Deploy PostgreSQL custom queries config
ansible.builtin.template:
src: postgres_queries.yaml.j2
dest: "{{ alloy_config_dir }}/postgres_queries.yaml"
mode: '0600'
notify: restart alloy
when: alloy_collect_postgres | default(false)
- name: Deploy alloy configuration
ansible.builtin.template:
src: config.alloy.j2

View file

@ -41,6 +41,9 @@ prometheus.remote_write "prometheus" {
// PostgreSQL exporter (read-only metrics via pg_monitor role)
prometheus.exporter.postgres "postgresql" {
data_source_names = ["postgresql://{{ alloy_postgres_user }}:{{ alloy_postgres_password | urlencode }}@{{ alloy_postgres_host }}:{{ alloy_postgres_port }}/{{ alloy_postgres_database }}?sslmode=disable"]
// Custom queries for vacuum and XID monitoring
custom_queries_config_path = "/opt/homebrew/etc/grafana-alloy/postgres_queries.yaml"
}
// Scrape PostgreSQL metrics

View file

@ -0,0 +1,20 @@
# {{ ansible_managed }}
# Custom PostgreSQL queries for XID exhaustion monitoring
pg_database_xid_age:
query: |
SELECT datname,
age(datfrozenxid) as xid_age,
current_setting('autovacuum_freeze_max_age')::bigint as freeze_max_age
FROM pg_database
WHERE datallowconn
metrics:
- datname:
usage: "LABEL"
description: "Database name"
- xid_age:
usage: "GAUGE"
description: "Age of oldest unfrozen transaction ID"
- freeze_max_age:
usage: "GAUGE"
description: "autovacuum_freeze_max_age setting"

View file

@ -500,7 +500,132 @@
],
"title": "Transactions Rate",
"type": "timeseries"
}
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"max": 200000000,
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 150000000 },
{ "color": "red", "value": 180000000 }
]
},
"unit": "short"
}
},
"gridPos": { "h": 6, "w": 12, "x": 0, "y": 20 },
"id": 9,
"options": {
"minVizHeight": 75,
"minVizWidth": 75,
"orientation": "horizontal",
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"showThresholdLabels": false,
"showThresholdMarkers": true,
"sizing": "auto"
},
"targets": [
{
"expr": "pg_database_xid_age_xid_age",
"legendFormat": "{{datname}}",
"refId": "A"
}
],
"title": "Transaction ID Age (XID Exhaustion Risk)",
"description": "Age of oldest unfrozen XID. Approaches 2 billion = wraparound danger. Yellow at 150M, Red at 180M (autovacuum_freeze_max_age default is 200M).",
"type": "gauge"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null }
]
},
"unit": "short"
}
},
"gridPos": { "h": 6, "w": 12, "x": 12, "y": 20 },
"id": 10,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "pg_database_xid_age_xid_age",
"legendFormat": "{{datname}}",
"refId": "A"
}
],
"title": "XID Age Over Time",
"type": "timeseries"
},
],
"schemaVersion": 39,
"tags": ["postgresql", "database"],