From fbaf322d1c280879a13ad32536b61fdfbafc7751 Mon Sep 17 00:00:00 2001 From: Greg Pattison Date: Mon, 29 Jun 2026 08:20:20 -0400 Subject: [PATCH] Modernize pgbouncer-mixin to grafonnet v11 and signals architecture --- pgbouncer-mixin/config.libsonnet | 10 ++ pgbouncer-mixin/dashboards.libsonnet | 6 +- .../{clusterOverview => clusterOverview.json} | 45 +++-- .../dashboards_out/{logs => logs.json} | 0 .../{overview => overview.json} | 161 +++++++++++------ pgbouncer-mixin/links.libsonnet | 6 +- pgbouncer-mixin/main.libsonnet | 11 +- pgbouncer-mixin/panels.libsonnet | 64 ++++--- pgbouncer-mixin/signals/cluster.libsonnet | 79 +++++++++ pgbouncer-mixin/signals/config.libsonnet | 41 +++++ pgbouncer-mixin/signals/connections.libsonnet | 129 ++++++++++++++ pgbouncer-mixin/signals/stats.libsonnet | 95 ++++++++++ pgbouncer-mixin/targets.libsonnet | 165 ------------------ pgbouncer-mixin/variables.libsonnet | 2 +- 14 files changed, 555 insertions(+), 259 deletions(-) rename pgbouncer-mixin/dashboards_out/{clusterOverview => clusterOverview.json} (89%) rename pgbouncer-mixin/dashboards_out/{logs => logs.json} (100%) rename pgbouncer-mixin/dashboards_out/{overview => overview.json} (83%) create mode 100644 pgbouncer-mixin/signals/cluster.libsonnet create mode 100644 pgbouncer-mixin/signals/config.libsonnet create mode 100644 pgbouncer-mixin/signals/connections.libsonnet create mode 100644 pgbouncer-mixin/signals/stats.libsonnet delete mode 100644 pgbouncer-mixin/targets.libsonnet diff --git a/pgbouncer-mixin/config.libsonnet b/pgbouncer-mixin/config.libsonnet index c4508010d..2fc73c6ba 100644 --- a/pgbouncer-mixin/config.libsonnet +++ b/pgbouncer-mixin/config.libsonnet @@ -1,4 +1,5 @@ { + local this = self, // any modular library should include as inputs: // 'dashboardNamePrefix' - Use as prefix for all Dashboards and (optional) rule groups // 'filteringSelector' - Static selector to apply to ALL dashboard variables of type query, panel queries, alerts and recording rules. @@ -16,6 +17,7 @@ dashboardTags: [self.uid], uid: 'pgbouncer', dashboardNamePrefix: '', + metricsSource: ['prometheus'], // additional params can be added if needed dashboardPeriod: 'now-1h', @@ -34,4 +36,12 @@ extraLogLabels: ['level'], logsVolumeGroupBy: 'level', showLogsVolume: true, + + // Signals configuration + signals+: { + connections: (import './signals/connections.libsonnet')(this), + stats: (import './signals/stats.libsonnet')(this), + config: (import './signals/config.libsonnet')(this), + cluster: (import './signals/cluster.libsonnet')(this), + }, } diff --git a/pgbouncer-mixin/dashboards.libsonnet b/pgbouncer-mixin/dashboards.libsonnet index 87aa95e90..87b626168 100644 --- a/pgbouncer-mixin/dashboards.libsonnet +++ b/pgbouncer-mixin/dashboards.libsonnet @@ -15,7 +15,7 @@ local logslib = import 'logs-lib/logs/main.libsonnet'; local panels = this.grafana.panels; local stat = g.panel.stat; { - overview: + 'overview.json': g.dashboard.new(prefix + 'PgBouncer overview') + g.dashboard.withPanels( g.util.grid.wrapPanels( @@ -45,7 +45,7 @@ local logslib = import 'logs-lib/logs/main.libsonnet'; ) // hide link to self + root.applyCommon(vars.singleInstance, uid + '-overview', tags, links { pgbouncerOverview+:: {} }, annotations, timezone, refresh, period), - clusterOverview: + 'clusterOverview.json': g.dashboard.new(prefix + 'PgBouncer cluster overview') + g.dashboard.withPanels( g.util.grid.wrapPanels( @@ -64,7 +64,7 @@ local logslib = import 'logs-lib/logs/main.libsonnet'; + if this.config.enableLokiLogs then { - logs: + 'logs.json': logslib.new( prefix + 'PgBouncer logs', datasourceName=this.grafana.variables.datasources.loki.name, diff --git a/pgbouncer-mixin/dashboards_out/clusterOverview b/pgbouncer-mixin/dashboards_out/clusterOverview.json similarity index 89% rename from pgbouncer-mixin/dashboards_out/clusterOverview rename to pgbouncer-mixin/dashboards_out/clusterOverview.json index 93a9008d6..eea01a26a 100644 --- a/pgbouncer-mixin/dashboards_out/clusterOverview +++ b/pgbouncer-mixin/dashboards_out/clusterOverview.json @@ -57,15 +57,18 @@ "sort": "desc" } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "topk by(database, instance, pgbouncer_cluster)($top_database_count, pgbouncer_pools_client_active_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",})", - "legendFormat": "{{pgbouncer_cluster}} - {{instance}} - {{database}}" + "expr": "topk by(database, instance, pgbouncer_cluster)($top_database_count, pgbouncer_pools_client_active_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\"})", + "format": "time_series", + "instant": false, + "legendFormat": "{{pgbouncer_cluster}} - {{instance}} - {{database}}", + "refId": "Top databases by active connections" } ], "title": "Top databases by active connections", @@ -133,15 +136,18 @@ "sort": "desc" } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "topk by(database, instance, pgbouncer_cluster)($top_database_count, rate(pgbouncer_stats_queries_pooled_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",}[$__rate_interval]))", - "legendFormat": "{{pgbouncer_cluster}} - {{instance}} - {{database}}" + "expr": "topk by(database, instance, pgbouncer_cluster)($top_database_count, rate(pgbouncer_stats_queries_pooled_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\"}[$__rate_interval]))", + "format": "time_series", + "instant": false, + "legendFormat": "{{pgbouncer_cluster}} - {{instance}} - {{database}}", + "refId": "Top databases by queries processed" } ], "title": "Top databases by queries processed", @@ -190,15 +196,18 @@ "sort": "desc" } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "topk by(database, instance, pgbouncer_cluster)($top_database_count, 1000 * increase(pgbouncer_stats_queries_duration_seconds_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",}[$__interval:]) / clamp_min(increase(pgbouncer_stats_queries_pooled_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",}[$__interval:]), 1))", - "legendFormat": "{{pgbouncer_cluster}} - {{instance}} - {{database}}" + "expr": "topk by(database, instance, pgbouncer_cluster)($top_database_count, 1000 * increase(pgbouncer_stats_queries_duration_seconds_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\"}[$__interval:]) / clamp_min(increase(pgbouncer_stats_queries_pooled_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\"}[$__interval:]), 1))", + "format": "time_series", + "instant": false, + "legendFormat": "{{pgbouncer_cluster}} - {{instance}} - {{database}}", + "refId": "Top databases by average query duration" } ], "title": "Top databases by average query duration", @@ -248,23 +257,29 @@ "sort": "desc" } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "topk by(database, instance, pgbouncer_cluster)($top_database_count, rate(pgbouncer_stats_received_bytes_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",}[$__rate_interval]))", - "legendFormat": "{{pgbouncer_cluster}} - {{instance}} - {{database}} - received" + "expr": "topk by(database, instance, pgbouncer_cluster)($top_database_count, rate(pgbouncer_stats_received_bytes_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\"}[$__rate_interval]))", + "format": "time_series", + "instant": false, + "legendFormat": "{{pgbouncer_cluster}} - {{instance}} - {{database}} - received", + "refId": "Top databases by network traffic received" }, { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "topk by(database, instance, pgbouncer_cluster)($top_database_count, rate(pgbouncer_stats_sent_bytes_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",}[$__rate_interval]))", - "legendFormat": "{{pgbouncer_cluster}} - {{instance}} - {{database}} - sent" + "expr": "topk by(database, instance, pgbouncer_cluster)($top_database_count, rate(pgbouncer_stats_sent_bytes_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\"}[$__rate_interval]))", + "format": "time_series", + "instant": false, + "legendFormat": "{{pgbouncer_cluster}} - {{instance}} - {{database}} - sent", + "refId": "Top databases by network traffic sent" } ], "title": "Top databases by network traffic", @@ -310,7 +325,7 @@ "label": "Pgbouncer_cluster", "multi": true, "name": "pgbouncer_cluster", - "query": "label_values(pgbouncer_databases_current_connections{,job=~\"$job\"}, pgbouncer_cluster)", + "query": "label_values(pgbouncer_databases_current_connections{job=~\"$job\"}, pgbouncer_cluster)", "refresh": 2, "sort": 1, "type": "query" diff --git a/pgbouncer-mixin/dashboards_out/logs b/pgbouncer-mixin/dashboards_out/logs.json similarity index 100% rename from pgbouncer-mixin/dashboards_out/logs rename to pgbouncer-mixin/dashboards_out/logs.json diff --git a/pgbouncer-mixin/dashboards_out/overview b/pgbouncer-mixin/dashboards_out/overview.json similarity index 83% rename from pgbouncer-mixin/dashboards_out/overview rename to pgbouncer-mixin/dashboards_out/overview.json index 6d33e1fa4..826e5c64c 100644 --- a/pgbouncer-mixin/dashboards_out/overview +++ b/pgbouncer-mixin/dashboards_out/overview.json @@ -55,14 +55,18 @@ "options": { "graphMode": "none" }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "sum(pgbouncer_pools_client_waiting_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",})" + "expr": "sum(\n pgbouncer_pools_client_waiting_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}\n)", + "format": "time_series", + "instant": false, + "legendFormat": "", + "refId": "Client waiting connections" } ], "title": "Client waiting connections", @@ -106,14 +110,18 @@ ] } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "sum(pgbouncer_pools_client_active_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",})" + "expr": "sum(\n pgbouncer_pools_client_active_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}\n)", + "format": "time_series", + "instant": false, + "legendFormat": "", + "refId": "Active client connections" } ], "title": "Active client connections", @@ -157,14 +165,18 @@ ] } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "sum(pgbouncer_pools_server_active_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",})" + "expr": "sum(\n pgbouncer_pools_server_active_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}\n)", + "format": "time_series", + "instant": false, + "legendFormat": "", + "refId": "Active server connections" } ], "title": "Active server connections", @@ -208,14 +220,18 @@ ] } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "sum(pgbouncer_databases_max_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",})" + "expr": "sum(\n pgbouncer_databases_max_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}\n)", + "format": "time_series", + "instant": false, + "legendFormat": "", + "refId": "Max database connections" } ], "title": "Max database connections", @@ -259,14 +275,18 @@ ] } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "sum(pgbouncer_config_max_user_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",})" + "expr": "sum(\n pgbouncer_config_max_user_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\"}\n)", + "format": "time_series", + "instant": false, + "legendFormat": "", + "refId": "Max user connections" } ], "title": "Max user connections", @@ -310,14 +330,18 @@ ] } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "sum(pgbouncer_config_max_client_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",})" + "expr": "sum(\n pgbouncer_config_max_client_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\"}\n)", + "format": "time_series", + "instant": false, + "legendFormat": "", + "refId": "Max client connections" } ], "title": "Max client connections", @@ -378,15 +402,18 @@ "sort": "desc" } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "rate(pgbouncer_stats_queries_pooled_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}[$__rate_interval])", - "legendFormat": "{{database}}" + "expr": "rate(pgbouncer_stats_queries_pooled_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}[$__rate_interval])", + "format": "time_series", + "instant": false, + "legendFormat": "{{database}}", + "refId": "Queries processed" } ], "title": "Queries processed", @@ -435,15 +462,18 @@ "sort": "desc" } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "1000 * increase(pgbouncer_stats_queries_duration_seconds_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}[$__interval:]) / clamp_min(increase(pgbouncer_stats_queries_pooled_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}[$__interval:]), 1)", - "legendFormat": "{{database}}" + "expr": "1000 * increase(pgbouncer_stats_queries_duration_seconds_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}[$__interval:]) / clamp_min(increase(pgbouncer_stats_queries_pooled_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}[$__interval:]), 1)", + "format": "time_series", + "instant": false, + "legendFormat": "{{database}}", + "refId": "Average query duration" } ], "title": "Queries average duration / $__interval", @@ -507,23 +537,29 @@ "sort": "desc" } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "rate(pgbouncer_stats_received_bytes_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}[$__rate_interval])", - "legendFormat": "{{database}} - received" + "expr": "rate(pgbouncer_stats_received_bytes_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}[$__rate_interval])", + "format": "time_series", + "instant": false, + "legendFormat": "{{database}} - received", + "refId": "Network received" }, { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "rate(pgbouncer_stats_sent_bytes_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}[$__rate_interval])", - "legendFormat": "{{database}} - sent" + "expr": "rate(pgbouncer_stats_sent_bytes_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}[$__rate_interval])", + "format": "time_series", + "instant": false, + "legendFormat": "{{database}} - sent", + "refId": "Network sent" } ], "title": "Network traffic", @@ -584,15 +620,18 @@ "sort": "desc" } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "rate(pgbouncer_stats_sql_transactions_pooled_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}[$__rate_interval])", - "legendFormat": "{{database}}" + "expr": "rate(pgbouncer_stats_sql_transactions_pooled_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}[$__rate_interval])", + "format": "time_series", + "instant": false, + "legendFormat": "{{database}}", + "refId": "SQL transaction rate" } ], "title": "SQL transaction rate", @@ -641,15 +680,18 @@ "sort": "desc" } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "1000 * increase(pgbouncer_stats_server_in_transaction_seconds_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}[$__interval:]) / clamp_min(increase(pgbouncer_stats_sql_transactions_pooled_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}[$__interval:]), 1)", - "legendFormat": "{{database}}" + "expr": "1000 * increase(pgbouncer_stats_server_in_transaction_seconds_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}[$__interval:]) / clamp_min(increase(pgbouncer_stats_sql_transactions_pooled_total{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}[$__interval:]), 1)", + "format": "time_series", + "instant": false, + "legendFormat": "{{database}}", + "refId": "Average transaction duration" } ], "title": "SQL average transaction duration / $__interval", @@ -711,39 +753,51 @@ "sort": "desc" } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "pgbouncer_pools_server_idle_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}", - "legendFormat": "{{database}} - idle" + "expr": "pgbouncer_pools_server_idle_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}", + "format": "time_series", + "instant": false, + "legendFormat": "{{database}} - idle", + "refId": "Server idle connections" }, { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "pgbouncer_pools_server_used_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}", - "legendFormat": "{{database}} - used" + "expr": "pgbouncer_pools_server_used_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}", + "format": "time_series", + "instant": false, + "legendFormat": "{{database}} - used", + "refId": "Server used connections" }, { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "pgbouncer_pools_server_login_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}", - "legendFormat": "{{database}} - login" + "expr": "pgbouncer_pools_server_login_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}", + "format": "time_series", + "instant": false, + "legendFormat": "{{database}} - login", + "refId": "Server login connections" }, { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "pgbouncer_pools_server_testing_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}", - "legendFormat": "{{database}} - testing" + "expr": "pgbouncer_pools_server_testing_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}", + "format": "time_series", + "instant": false, + "legendFormat": "{{database}} - testing", + "refId": "Server testing connections" } ], "title": "Server connections", @@ -804,15 +858,18 @@ "sort": "desc" } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "pgbouncer_pools_client_active_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}", - "legendFormat": "{{database}}" + "expr": "pgbouncer_pools_client_active_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}", + "format": "time_series", + "instant": false, + "legendFormat": "{{database}}", + "refId": "Active client connections" } ], "title": "Active client connections", @@ -861,15 +918,18 @@ "sort": "desc" } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "pgbouncer_pools_client_waiting_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}", - "legendFormat": "{{database}}" + "expr": "pgbouncer_pools_client_waiting_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}", + "format": "time_series", + "instant": false, + "legendFormat": "{{database}}", + "refId": "Client waiting connections" } ], "title": "Waiting clients", @@ -918,15 +978,18 @@ "sort": "desc" } }, - "pluginVersion": "v11.0.0", + "pluginVersion": "v11.4.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "${prometheus_datasource}" }, - "expr": "pgbouncer_pools_client_maxwait_seconds{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\",}", - "legendFormat": "{{database}}" + "expr": "pgbouncer_pools_client_maxwait_seconds{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\",instance=~\"$instance\",database=~\"$database\"}", + "format": "time_series", + "instant": false, + "legendFormat": "{{database}}", + "refId": "Max client wait time" } ], "title": "Max client wait time", @@ -972,7 +1035,7 @@ "label": "Pgbouncer_cluster", "multi": true, "name": "pgbouncer_cluster", - "query": "label_values(pgbouncer_databases_current_connections{,job=~\"$job\"}, pgbouncer_cluster)", + "query": "label_values(pgbouncer_databases_current_connections{job=~\"$job\"}, pgbouncer_cluster)", "refresh": 2, "sort": 1, "type": "query" @@ -987,7 +1050,7 @@ "label": "Instance", "multi": false, "name": "instance", - "query": "label_values(pgbouncer_databases_current_connections{,job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\"}, instance)", + "query": "label_values(pgbouncer_databases_current_connections{job=~\"$job\",pgbouncer_cluster=~\"$pgbouncer_cluster\"}, instance)", "refresh": 2, "sort": 1, "type": "query" diff --git a/pgbouncer-mixin/links.libsonnet b/pgbouncer-mixin/links.libsonnet index 8cf725f75..9808914d3 100644 --- a/pgbouncer-mixin/links.libsonnet +++ b/pgbouncer-mixin/links.libsonnet @@ -4,17 +4,17 @@ local g = import './g.libsonnet'; new(this): { pgbouncerOverview: - link.link.new('PgBouncer overview', '/d/' + this.grafana.dashboards.overview.uid) + link.link.new('PgBouncer overview', '/d/' + this.grafana.dashboards['overview.json'].uid) + link.link.options.withKeepTime(true), pgbouncerClusterOverview: - link.link.new('PgBouncer cluster overview', '/d/' + this.grafana.dashboards.clusterOverview.uid) + link.link.new('PgBouncer cluster overview', '/d/' + this.grafana.dashboards['clusterOverview.json'].uid) + link.link.options.withKeepTime(true), } + if this.config.enableLokiLogs then { logs: - link.link.new('PgBouncer logs', '/d/' + this.grafana.dashboards.logs.uid) + link.link.new('PgBouncer logs', '/d/' + this.grafana.dashboards['logs.json'].uid) + link.link.options.withKeepTime(true), } else {}, diff --git a/pgbouncer-mixin/main.libsonnet b/pgbouncer-mixin/main.libsonnet index 8ac3be57c..665d9773d 100644 --- a/pgbouncer-mixin/main.libsonnet +++ b/pgbouncer-mixin/main.libsonnet @@ -4,8 +4,8 @@ local dashboards = import './dashboards.libsonnet'; local g = import './g.libsonnet'; local links = import './links.libsonnet'; local panels = import './panels.libsonnet'; -local targets = import './targets.libsonnet'; local variables = import './variables.libsonnet'; +local commonlib = import 'common-lib/common/main.libsonnet'; { @@ -17,10 +17,17 @@ local variables = import './variables.libsonnet'; local this = self, config: config, + signals: + { + [sig]: commonlib.signals.unmarshallJsonMulti( + this.config.signals[sig], + type=this.config.metricsSource + ) + for sig in std.objectFields(this.config.signals) + }, grafana: { variables: variables.new(this, varMetric='pgbouncer_databases_current_connections'), - targets: targets.new(this), annotations: {}, links: links.new(this), panels: panels.new(this), diff --git a/pgbouncer-mixin/panels.libsonnet b/pgbouncer-mixin/panels.libsonnet index 5c059c5aa..ada9b7d51 100644 --- a/pgbouncer-mixin/panels.libsonnet +++ b/pgbouncer-mixin/panels.libsonnet @@ -1,10 +1,9 @@ local g = import './g.libsonnet'; local commonlib = import 'common-lib/common/main.libsonnet'; -local utils = commonlib.utils; { new(this): { - local t = this.grafana.targets, + local signals = this.signals, local stat = g.panel.stat, local alertList = g.panel.alertList, @@ -12,7 +11,9 @@ local utils = commonlib.utils; clientsWaitingConnections: commonlib.panels.generic.stat.base.new( 'Client waiting connections', - targets=[t.clientsWaitingConnections], + targets=[ + signals.connections.pools_client_waiting_connections.withExprWrappersMixin(['sum(', ')']).withLegendFormat('').asTarget(), + ], description='Current number of client connections waiting on a server connection.' ) + stat.options.withGraphMode('none') @@ -28,35 +29,45 @@ local utils = commonlib.utils; activeClientConnections: commonlib.panels.generic.stat.info.new( 'Active client connections', - targets=[t.activeClientConnections], + targets=[ + signals.connections.pools_client_active_connections.withExprWrappersMixin(['sum(', ')']).withLegendFormat('').asTarget(), + ], description='Current number of active client connections.' ) + stat.options.withGraphMode('none'), activeServerConnections: commonlib.panels.generic.stat.info.new( 'Active server connections', - targets=[t.activeServerConnections], + targets=[ + signals.connections.pools_server_active_connections.withExprWrappersMixin(['sum(', ')']).withLegendFormat('').asTarget(), + ], description='Current number of client connections that are linked to a server connection and able to process queries.' ) + stat.options.withGraphMode('none'), maxDatabaseConnections: commonlib.panels.generic.stat.info.new( 'Max database connections', - targets=[t.maxDatabaseConnections], + targets=[ + signals.connections.databases_max_connections.withExprWrappersMixin(['sum(', ')']).withLegendFormat('').asTarget(), + ], description='Maximum number of allowed connections for database.' ) + stat.options.withGraphMode('none'), maxUserConnections: commonlib.panels.generic.stat.info.new( 'Max user connections', - targets=[t.maxUserConnections], + targets=[ + signals.config.config_max_user_connections.withExprWrappersMixin(['sum(', ')']).withLegendFormat('').asTarget(), + ], description='Maximum number of server connections per user allowed.' ) + stat.options.withGraphMode('none'), maxClientConnections: commonlib.panels.generic.stat.info.new( 'Max client connections', - targets=[t.maxClientConnections], + targets=[ + signals.config.config_max_client_connections.withExprWrappersMixin(['sum(', ')']).withLegendFormat('').asTarget(), + ], description='Maximum number of client connections allowed.' ) + stat.options.withGraphMode('none'), @@ -64,7 +75,7 @@ local utils = commonlib.utils; queriesPooled: commonlib.panels.generic.timeSeries.base.new( 'Queries processed', - targets=[t.queriesPooled], + targets=[signals.stats.stats_queries_pooled_total.asTarget()], description=||| Rate of SQL queries pooled by PgBouncer. ||| @@ -74,7 +85,7 @@ local utils = commonlib.utils; queryDuration: commonlib.panels.generic.timeSeries.base.new( 'Queries average duration / $__interval', - targets=[t.queryDuration], + targets=[signals.stats.stats_query_avg_duration.asTarget()], description=||| Average duration of queries being processed by PgBouncer. ||| @@ -84,7 +95,10 @@ local utils = commonlib.utils; networkTraffic: commonlib.panels.network.timeSeries.traffic.new( 'Network traffic', - targets=[t.networkTrafficRecieved, t.networkTrafficSent], + targets=[ + signals.stats.stats_received_bytes_total.asTarget(), + signals.stats.stats_sent_bytes_total.asTarget(), + ], description=||| Volume in bytes of network traffic received by PgBouncer. ||| @@ -96,7 +110,7 @@ local utils = commonlib.utils; transactionRate: commonlib.panels.generic.timeSeries.base.new( 'SQL transaction rate', - targets=[t.transactionRate], + targets=[signals.stats.stats_sql_transactions_pooled_total.asTarget()], description=||| Rate of SQL transactions pooled. ||| @@ -106,7 +120,7 @@ local utils = commonlib.utils; transactionAverageDuration: commonlib.panels.generic.timeSeries.base.new( 'SQL average transaction duration / $__interval', - targets=[t.transactionAverageDuration], + targets=[signals.stats.stats_transaction_avg_duration.asTarget()], description=||| Average duration of SQL transactions pooled. ||| @@ -116,7 +130,12 @@ local utils = commonlib.utils; serverConnections: commonlib.panels.generic.timeSeries.base.new( 'Server connections', - targets=[t.serverIdleConnections, t.serverUsedConnections, t.serverLoginConnections, t.serverTestingConnections], + targets=[ + signals.connections.pools_server_idle_connections.asTarget(), + signals.connections.pools_server_used_connections.asTarget(), + signals.connections.pools_server_login_connections.asTarget(), + signals.connections.pools_server_testing_connections.asTarget(), + ], description=||| Number of various server connection states. ||| @@ -128,7 +147,7 @@ local utils = commonlib.utils; granularActiveClientConnections: commonlib.panels.generic.timeSeries.base.new( 'Active client connections', - targets=[t.granularActiveClientConnections], + targets=[signals.connections.pools_client_active_connections.asTarget()], description=||| Current number of active client connections. ||| @@ -138,7 +157,7 @@ local utils = commonlib.utils; clientsWaiting: commonlib.panels.generic.timeSeries.base.new( 'Waiting clients', - targets=[t.clientsWaiting], + targets=[signals.connections.pools_client_waiting_connections.asTarget()], description=||| Current number of client connections waiting on a server connection. ||| @@ -148,7 +167,7 @@ local utils = commonlib.utils; maxClientWaitTime: commonlib.panels.generic.timeSeries.base.new( 'Max client wait time', - targets=[t.maxClientWaitTime], + targets=[signals.connections.pools_client_maxwait_seconds.asTarget()], description=||| Age of the oldest unserved client connection in seconds. ||| @@ -162,7 +181,7 @@ local utils = commonlib.utils; topDatabaseActiveConnection: commonlib.panels.generic.timeSeries.base.new( 'Top databases by active connections', - targets=[t.topDatabaseActiveConnection], + targets=[signals.cluster.top_database_active_connection.asTarget()], description=||| Top databases by current number of active client connections. ||| @@ -171,7 +190,7 @@ local utils = commonlib.utils; topDatabaseQueryPooled: commonlib.panels.generic.timeSeries.base.new( 'Top databases by queries processed', - targets=[t.topDatabaseQueryProcessed], + targets=[signals.cluster.top_database_query_processed.asTarget()], description=||| Top databases by rate of SQL queries pooled by PgBouncer. ||| @@ -180,7 +199,7 @@ local utils = commonlib.utils; topDatabaseQueryDuration: commonlib.panels.generic.timeSeries.base.new( 'Top databases by average query duration', - targets=[t.topDatabaseQueryDuration], + targets=[signals.cluster.top_database_query_duration.asTarget()], description=||| Top databases by average duration of queries being processed by PgBouncer. ||| @@ -189,7 +208,10 @@ local utils = commonlib.utils; topDatabaseNetworkTraffic: commonlib.panels.generic.timeSeries.base.new( 'Top databases by network traffic', - targets=[t.topDatabaseNetworkTrafficReceived, t.topDatabaseNetworkTrafficSent], + targets=[ + signals.cluster.top_database_network_received.asTarget(), + signals.cluster.top_database_network_sent.asTarget(), + ], description=||| Top databases by volume of network traffic. ||| diff --git a/pgbouncer-mixin/signals/cluster.libsonnet b/pgbouncer-mixin/signals/cluster.libsonnet new file mode 100644 index 000000000..c12c5ad2d --- /dev/null +++ b/pgbouncer-mixin/signals/cluster.libsonnet @@ -0,0 +1,79 @@ +// Cluster-overview "top database" signals for PgBouncer. +// These reproduce the legacy topk panels: the inner selector is group-only +// (job, pgbouncer_cluster via %(queriesSelectorGroupOnly)s) and the topk by-clause / +// $top_database_count parameter are baked into raw expressions. +function(this) + { + filteringSelector: this.filteringSelector, + groupLabels: this.groupLabels, + instanceLabels: this.instanceLabels, + enableLokiLogs: this.enableLokiLogs, + aggLevel: 'none', + aggFunction: 'sum', + alertsInterval: '5m', + discoveryMetric: { + prometheus: 'pgbouncer_databases_current_connections', + }, + signals: { + top_database_active_connection: { + name: 'Top databases by active connections', + description: 'Top databases by current number of active client connections.', + type: 'raw', + unit: 'conn', + sources: { + prometheus: { + expr: 'topk by(database, instance, pgbouncer_cluster)($top_database_count, pgbouncer_pools_client_active_connections{%(queriesSelectorGroupOnly)s})', + legendCustomTemplate: '{{pgbouncer_cluster}} - {{instance}} - {{database}}', + }, + }, + }, + top_database_query_processed: { + name: 'Top databases by queries processed', + description: 'Top databases by rate of SQL queries pooled by PgBouncer.', + type: 'raw', + unit: 'ops', + sources: { + prometheus: { + expr: 'topk by(database, instance, pgbouncer_cluster)($top_database_count, rate(pgbouncer_stats_queries_pooled_total{%(queriesSelectorGroupOnly)s}[$__rate_interval]))', + legendCustomTemplate: '{{pgbouncer_cluster}} - {{instance}} - {{database}}', + }, + }, + }, + top_database_query_duration: { + name: 'Top databases by average query duration', + description: 'Top databases by average duration of queries being processed by PgBouncer.', + type: 'raw', + unit: 's', + sources: { + prometheus: { + expr: 'topk by(database, instance, pgbouncer_cluster)($top_database_count, 1000 * increase(pgbouncer_stats_queries_duration_seconds_total{%(queriesSelectorGroupOnly)s}[$__interval:]) / clamp_min(increase(pgbouncer_stats_queries_pooled_total{%(queriesSelectorGroupOnly)s}[$__interval:]), 1))', + legendCustomTemplate: '{{pgbouncer_cluster}} - {{instance}} - {{database}}', + }, + }, + }, + top_database_network_received: { + name: 'Top databases by network traffic received', + description: 'Top databases by volume of network traffic received.', + type: 'raw', + unit: 'Bps', + sources: { + prometheus: { + expr: 'topk by(database, instance, pgbouncer_cluster)($top_database_count, rate(pgbouncer_stats_received_bytes_total{%(queriesSelectorGroupOnly)s}[$__rate_interval]))', + legendCustomTemplate: '{{pgbouncer_cluster}} - {{instance}} - {{database}} - received', + }, + }, + }, + top_database_network_sent: { + name: 'Top databases by network traffic sent', + description: 'Top databases by volume of network traffic sent.', + type: 'raw', + unit: 'Bps', + sources: { + prometheus: { + expr: 'topk by(database, instance, pgbouncer_cluster)($top_database_count, rate(pgbouncer_stats_sent_bytes_total{%(queriesSelectorGroupOnly)s}[$__rate_interval]))', + legendCustomTemplate: '{{pgbouncer_cluster}} - {{instance}} - {{database}} - sent', + }, + }, + }, + }, + } diff --git a/pgbouncer-mixin/signals/config.libsonnet b/pgbouncer-mixin/signals/config.libsonnet new file mode 100644 index 000000000..a4758402c --- /dev/null +++ b/pgbouncer-mixin/signals/config.libsonnet @@ -0,0 +1,41 @@ +// Per-instance configuration limit signals for PgBouncer. +// These are instance-scoped settings (not per-database), so instanceLabels is +// pureInstanceLabels (['instance']) -> selector job, pgbouncer_cluster, instance, +// reproducing the legacy instanceQueriesSelector. aggLevel 'none'; panels supply sum(). +function(this) + { + filteringSelector: this.filteringSelector, + groupLabels: this.groupLabels, + instanceLabels: this.pureInstanceLabels, + enableLokiLogs: this.enableLokiLogs, + aggLevel: 'none', + aggFunction: 'sum', + alertsInterval: '5m', + discoveryMetric: { + prometheus: 'pgbouncer_databases_current_connections', + }, + signals: { + config_max_user_connections: { + name: 'Max user connections', + description: 'Maximum number of server connections per user allowed.', + type: 'gauge', + unit: 'short', + sources: { + prometheus: { + expr: 'pgbouncer_config_max_user_connections{%(queriesSelector)s}', + }, + }, + }, + config_max_client_connections: { + name: 'Max client connections', + description: 'Maximum number of client connections allowed.', + type: 'gauge', + unit: 'short', + sources: { + prometheus: { + expr: 'pgbouncer_config_max_client_connections{%(queriesSelector)s}', + }, + }, + }, + }, + } diff --git a/pgbouncer-mixin/signals/connections.libsonnet b/pgbouncer-mixin/signals/connections.libsonnet new file mode 100644 index 000000000..81d7fa25c --- /dev/null +++ b/pgbouncer-mixin/signals/connections.libsonnet @@ -0,0 +1,129 @@ +// Connection pool signals for PgBouncer (per-database group) +// Selector: job, pgbouncer_cluster, instance, database. +// aggLevel is kept 'none' so panels supply aggregation explicitly (matching legacy sum/raw). +function(this) + { + filteringSelector: this.filteringSelector, + groupLabels: this.groupLabels, + instanceLabels: this.instanceLabels, + enableLokiLogs: this.enableLokiLogs, + aggLevel: 'none', + aggFunction: 'sum', + alertsInterval: '5m', + discoveryMetric: { + prometheus: 'pgbouncer_databases_current_connections', + }, + signals: { + // Client connection states + pools_client_waiting_connections: { + name: 'Client waiting connections', + description: 'Current number of client connections waiting on a server connection.', + type: 'gauge', + unit: 'short', + sources: { + prometheus: { + expr: 'pgbouncer_pools_client_waiting_connections{%(queriesSelector)s}', + legendCustomTemplate: '{{database}}', + }, + }, + }, + pools_client_active_connections: { + name: 'Active client connections', + description: 'Current number of active client connections.', + type: 'gauge', + unit: 'short', + sources: { + prometheus: { + expr: 'pgbouncer_pools_client_active_connections{%(queriesSelector)s}', + legendCustomTemplate: '{{database}}', + }, + }, + }, + pools_client_maxwait_seconds: { + name: 'Max client wait time', + description: 'Age of the oldest unserved client connection in seconds.', + type: 'gauge', + unit: 's', + sources: { + prometheus: { + expr: 'pgbouncer_pools_client_maxwait_seconds{%(queriesSelector)s}', + legendCustomTemplate: '{{database}}', + }, + }, + }, + + // Server connection states + pools_server_active_connections: { + name: 'Active server connections', + description: 'Current number of server connections linked to a client connection.', + type: 'gauge', + unit: 'short', + sources: { + prometheus: { + expr: 'pgbouncer_pools_server_active_connections{%(queriesSelector)s}', + }, + }, + }, + pools_server_idle_connections: { + name: 'Server idle connections', + description: 'Current number of server connections idle and ready for a client query.', + type: 'gauge', + unit: 'short', + sources: { + prometheus: { + expr: 'pgbouncer_pools_server_idle_connections{%(queriesSelector)s}', + legendCustomTemplate: '{{database}} - idle', + }, + }, + }, + pools_server_used_connections: { + name: 'Server used connections', + description: 'Current number of server connections idle more than server_check_delay.', + type: 'gauge', + unit: 'short', + sources: { + prometheus: { + expr: 'pgbouncer_pools_server_used_connections{%(queriesSelector)s}', + legendCustomTemplate: '{{database}} - used', + }, + }, + }, + pools_server_login_connections: { + name: 'Server login connections', + description: 'Current number of server connections in login phase.', + type: 'gauge', + unit: 'short', + sources: { + prometheus: { + expr: 'pgbouncer_pools_server_login_connections{%(queriesSelector)s}', + legendCustomTemplate: '{{database}} - login', + }, + }, + }, + pools_server_testing_connections: { + name: 'Server testing connections', + description: 'Current number of server connections being tested.', + type: 'gauge', + unit: 'short', + sources: { + prometheus: { + expr: 'pgbouncer_pools_server_testing_connections{%(queriesSelector)s}', + legendCustomTemplate: '{{database}} - testing', + }, + }, + }, + + // Per-database connection limit + databases_max_connections: { + name: 'Max database connections', + description: 'Maximum number of server connections allowed per database.', + type: 'gauge', + unit: 'short', + sources: { + prometheus: { + expr: 'pgbouncer_databases_max_connections{%(queriesSelector)s}', + }, + }, + }, + }, + } diff --git a/pgbouncer-mixin/signals/stats.libsonnet b/pgbouncer-mixin/signals/stats.libsonnet new file mode 100644 index 000000000..9e4f0f3f4 --- /dev/null +++ b/pgbouncer-mixin/signals/stats.libsonnet @@ -0,0 +1,95 @@ +// Query, transaction, and network statistics signals for PgBouncer (per-database group). +// Selector: job, pgbouncer_cluster, instance, database. aggLevel 'none'; counters default +// to rate() in asTarget(); the average-duration signals are raw (ratio-of-increases). +function(this) + { + filteringSelector: this.filteringSelector, + groupLabels: this.groupLabels, + instanceLabels: this.instanceLabels, + enableLokiLogs: this.enableLokiLogs, + aggLevel: 'none', + aggFunction: 'sum', + alertsInterval: '5m', + discoveryMetric: { + prometheus: 'pgbouncer_stats_queries_pooled_total', + }, + signals: { + // Query statistics + stats_queries_pooled_total: { + name: 'Queries processed', + description: 'Rate of SQL queries pooled by PgBouncer.', + type: 'counter', + unit: 'ops', + sources: { + prometheus: { + expr: 'pgbouncer_stats_queries_pooled_total{%(queriesSelector)s}', + legendCustomTemplate: '{{database}}', + }, + }, + }, + stats_query_avg_duration: { + name: 'Average query duration', + description: 'Average duration of queries processed by PgBouncer per interval.', + type: 'raw', + unit: 'ms', + sources: { + prometheus: { + expr: '1000 * increase(pgbouncer_stats_queries_duration_seconds_total{%(queriesSelector)s}[$__interval:]) / clamp_min(increase(pgbouncer_stats_queries_pooled_total{%(queriesSelector)s}[$__interval:]), 1)', + legendCustomTemplate: '{{database}}', + }, + }, + }, + + // Transaction statistics + stats_sql_transactions_pooled_total: { + name: 'SQL transaction rate', + description: 'Rate of SQL transactions pooled by PgBouncer.', + type: 'counter', + unit: 'ops', + sources: { + prometheus: { + expr: 'pgbouncer_stats_sql_transactions_pooled_total{%(queriesSelector)s}', + legendCustomTemplate: '{{database}}', + }, + }, + }, + stats_transaction_avg_duration: { + name: 'Average transaction duration', + description: 'Average duration of SQL transactions pooled by PgBouncer per interval.', + type: 'raw', + unit: 'ms', + sources: { + prometheus: { + expr: '1000 * increase(pgbouncer_stats_server_in_transaction_seconds_total{%(queriesSelector)s}[$__interval:]) / clamp_min(increase(pgbouncer_stats_sql_transactions_pooled_total{%(queriesSelector)s}[$__interval:]), 1)', + legendCustomTemplate: '{{database}}', + }, + }, + }, + + // Network statistics + stats_received_bytes_total: { + name: 'Network received', + description: 'Rate of bytes received by PgBouncer from clients.', + type: 'counter', + unit: 'Bps', + sources: { + prometheus: { + expr: 'pgbouncer_stats_received_bytes_total{%(queriesSelector)s}', + legendCustomTemplate: '{{database}} - received', + }, + }, + }, + stats_sent_bytes_total: { + name: 'Network sent', + description: 'Rate of bytes sent by PgBouncer to clients.', + type: 'counter', + unit: 'Bps', + sources: { + prometheus: { + expr: 'pgbouncer_stats_sent_bytes_total{%(queriesSelector)s}', + legendCustomTemplate: '{{database}} - sent', + }, + }, + }, + }, + } diff --git a/pgbouncer-mixin/targets.libsonnet b/pgbouncer-mixin/targets.libsonnet deleted file mode 100644 index 890472155..000000000 --- a/pgbouncer-mixin/targets.libsonnet +++ /dev/null @@ -1,165 +0,0 @@ -local g = import './g.libsonnet'; -local prometheusQuery = g.query.prometheus; -local commonlib = import 'common-lib/common/main.libsonnet'; -local utils = commonlib.utils { - labelsToPanelLegend(labels): std.join(' - ', ['{{%s}}' % [label] for label in labels]), -}; -local lokiQuery = g.query.loki; - -{ - new(this): { - local vars = this.grafana.variables, - local config = this.config, - - clientsWaitingConnections: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'sum(pgbouncer_pools_client_waiting_connections{%(queriesSelector)s})' % vars - ), - activeClientConnections: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'sum(pgbouncer_pools_client_active_connections{%(queriesSelector)s})' % vars - ), - activeServerConnections: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'sum(pgbouncer_pools_server_active_connections{%(queriesSelector)s})' % vars - ), - maxDatabaseConnections: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'sum(pgbouncer_databases_max_connections{%(queriesSelector)s})' % vars - ), - maxUserConnections: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'sum(pgbouncer_config_max_user_connections{%(instanceQueriesSelector)s})' % vars - ), - maxClientConnections: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'sum(pgbouncer_config_max_client_connections{%(instanceQueriesSelector)s})' % vars - ), - queriesPooled: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'rate(pgbouncer_stats_queries_pooled_total{%(queriesSelector)s}[$__rate_interval])' % vars - ) - + prometheusQuery.withLegendFormat('%s' % utils.labelsToPanelLegend(this.config.legendLabels)), - queryDuration: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - '1000 * increase(pgbouncer_stats_queries_duration_seconds_total{%(queriesSelector)s}[$__interval:]) / clamp_min(increase(pgbouncer_stats_queries_pooled_total{%(queriesSelector)s}[$__interval:]), 1)' % vars - ) - + prometheusQuery.withLegendFormat('%s' % utils.labelsToPanelLegend(this.config.legendLabels)), - - networkTrafficRecieved: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'rate(pgbouncer_stats_received_bytes_total{%(queriesSelector)s}[$__rate_interval])' % vars - ) - + prometheusQuery.withLegendFormat('%s - received' % utils.labelsToPanelLegend(this.config.legendLabels)), - - networkTrafficSent: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'rate(pgbouncer_stats_sent_bytes_total{%(queriesSelector)s}[$__rate_interval])' % vars - ) - + prometheusQuery.withLegendFormat('%s - sent' % utils.labelsToPanelLegend(this.config.legendLabels)), - - transactionRate: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'rate(pgbouncer_stats_sql_transactions_pooled_total{%(queriesSelector)s}[$__rate_interval])' % vars - ) - + prometheusQuery.withLegendFormat('%s' % utils.labelsToPanelLegend(this.config.legendLabels)), - - transactionAverageDuration: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - '1000 * increase(pgbouncer_stats_server_in_transaction_seconds_total{%(queriesSelector)s}[$__interval:]) / clamp_min(increase(pgbouncer_stats_sql_transactions_pooled_total{%(queriesSelector)s}[$__interval:]), 1)' % vars - ) - + prometheusQuery.withLegendFormat('%s' % utils.labelsToPanelLegend(this.config.legendLabels)), - - serverIdleConnections: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'pgbouncer_pools_server_idle_connections{%(queriesSelector)s}' % vars - ) - + prometheusQuery.withLegendFormat('%s - idle' % utils.labelsToPanelLegend(this.config.legendLabels)), - - serverUsedConnections: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'pgbouncer_pools_server_used_connections{%(queriesSelector)s}' % vars - ) - + prometheusQuery.withLegendFormat('%s - used' % utils.labelsToPanelLegend(this.config.legendLabels)), - - serverTestingConnections: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'pgbouncer_pools_server_testing_connections{%(queriesSelector)s}' % vars - ) - + prometheusQuery.withLegendFormat('%s - testing' % utils.labelsToPanelLegend(this.config.legendLabels)), - - serverLoginConnections: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'pgbouncer_pools_server_login_connections{%(queriesSelector)s}' % vars - ) - + prometheusQuery.withLegendFormat('%s - login' % utils.labelsToPanelLegend(this.config.legendLabels)), - - granularActiveClientConnections: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'pgbouncer_pools_client_active_connections{%(queriesSelector)s}' % vars - ) - + prometheusQuery.withLegendFormat('%s' % utils.labelsToPanelLegend(this.config.legendLabels)), - - clientsWaiting: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'pgbouncer_pools_client_waiting_connections{%(queriesSelector)s}' % vars - ) - + prometheusQuery.withLegendFormat('%s' % utils.labelsToPanelLegend(this.config.legendLabels)), - - maxClientWaitTime: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'pgbouncer_pools_client_maxwait_seconds{%(queriesSelector)s}' % vars - ) - + prometheusQuery.withLegendFormat('%s' % utils.labelsToPanelLegend(this.config.legendLabels)), - - topDatabaseActiveConnection: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'topk by(database, instance, pgbouncer_cluster)($top_database_count, pgbouncer_pools_client_active_connections{%(clusterQuerySelector)s})' % vars - ) - + prometheusQuery.withLegendFormat('%s' % utils.labelsToPanelLegend(this.config.clusterLegendLabel)), - topDatabaseQueryProcessed: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'topk by(database, instance, pgbouncer_cluster)($top_database_count, rate(pgbouncer_stats_queries_pooled_total{%(clusterQuerySelector)s}[$__rate_interval]))' % vars - ) - + prometheusQuery.withLegendFormat('%s' % utils.labelsToPanelLegend(this.config.clusterLegendLabel)), - topDatabaseQueryDuration: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'topk by(database, instance, pgbouncer_cluster)($top_database_count, 1000 * increase(pgbouncer_stats_queries_duration_seconds_total{%(clusterQuerySelector)s}[$__interval:]) / clamp_min(increase(pgbouncer_stats_queries_pooled_total{%(clusterQuerySelector)s}[$__interval:]), 1))' % vars - ) - + prometheusQuery.withLegendFormat('%s' % utils.labelsToPanelLegend(this.config.clusterLegendLabel)), - topDatabaseNetworkTrafficReceived: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'topk by(database, instance, pgbouncer_cluster)($top_database_count, rate(pgbouncer_stats_received_bytes_total{%(clusterQuerySelector)s}[$__rate_interval]))' % vars - ) - + prometheusQuery.withLegendFormat('%s - received' % utils.labelsToPanelLegend(this.config.clusterLegendLabel)), - topDatabaseNetworkTrafficSent: - prometheusQuery.new( - '${' + vars.datasources.prometheus.name + '}', - 'topk by(database, instance, pgbouncer_cluster)($top_database_count, rate(pgbouncer_stats_sent_bytes_total{%(clusterQuerySelector)s}[$__rate_interval]))' % vars - ) - + prometheusQuery.withLegendFormat('%s - sent' % utils.labelsToPanelLegend(this.config.clusterLegendLabel)), - }, -} diff --git a/pgbouncer-mixin/variables.libsonnet b/pgbouncer-mixin/variables.libsonnet index beefbbc96..8225ae771 100644 --- a/pgbouncer-mixin/variables.libsonnet +++ b/pgbouncer-mixin/variables.libsonnet @@ -44,7 +44,7 @@ local utils = commonlib.utils; asc=true, caseInsensitive=false ); - std.mapWithIndex(chainVarProto, utils.chainLabels(groupLabels + instanceLabels, [filteringSelector])), + std.mapWithIndex(chainVarProto, utils.chainLabels(groupLabels + instanceLabels, if filteringSelector != '' then [filteringSelector] else [])), datasources: { prometheus: var.datasource.new('prometheus_datasource', 'prometheus')