From 6e60cc60bcd784a256daf06a0c107c54a674365e Mon Sep 17 00:00:00 2001 From: "Chris (ChrisJr404)" <11917633+ChrisJr404@users.noreply.github.com> Date: Thu, 27 Aug 2026 10:24:18 -0400 Subject: [PATCH] feat(stats): add banned gauge to pool metrics --- pgdog/src/stats/pools.rs | 44 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/pgdog/src/stats/pools.rs b/pgdog/src/stats/pools.rs index 1d3e7635e..1df65f64f 100644 --- a/pgdog/src/stats/pools.rs +++ b/pgdog/src/stats/pools.rs @@ -52,6 +52,7 @@ impl Pools { let mut maxwait = vec![]; let mut errors = vec![]; let mut out_of_sync = vec![]; + let mut banned = vec![]; let mut total_xact_count = vec![]; let mut total_xact_2pc_count = vec![]; let mut avg_xact_count = vec![]; @@ -98,7 +99,7 @@ impl Pools { for (user, cluster) in databases().all() { for (shard_num, shard) in cluster.shards().iter().enumerate() { - for (role, pool) in shard.pools_with_roles() { + for (role, ban, pool) in shard.pools_with_roles_and_bans() { let state = pool.state(); let labels = vec![ ("user".into(), user.user.clone()), @@ -149,6 +150,11 @@ impl Pools { measurement: state.out_of_sync.into(), }); + banned.push(Measurement { + labels: labels.clone(), + measurement: (ban.banned() as i64).into(), + }); + let stats = state.stats; let totals = stats.counts; let averages = stats.averages; @@ -449,6 +455,14 @@ impl Pools { metric_type: Some("counter".into()), })); + metrics.push(Metric::new(PoolMetric { + name: "banned".into(), + measurements: banned, + help: "Whether the pool is currently banned from serving traffic (1 = banned, 0 = available).".into(), + unit: None, + metric_type: None, + })); + metrics.push(Metric::new(PoolMetric { name: "total_xact_count".into(), measurements: total_xact_count, @@ -841,6 +855,34 @@ mod tests { assert_eq!(lines[2], "# HELP sv_active Active servers per pool"); assert_eq!(lines[3], "sv_active{user=\"alice\",database=\"app\"} 5"); } + + #[test] + fn banned_metric_renders_as_gauge() { + config::set(ConfigAndUsers::default()).unwrap(); + + let metric = PoolMetric { + name: "banned".into(), + measurements: vec![Measurement { + labels: vec![ + ("database".into(), "app".into()), + ("role".into(), "replica".into()), + ], + measurement: (true as i64).into(), + }], + help: "Whether the pool is currently banned from serving traffic (1 = banned, 0 = available).".into(), + unit: None, + metric_type: None, + }; + + let rendered = Metric::new(metric).to_string(); + let lines: Vec<&str> = rendered.lines().collect(); + assert_eq!(lines[0], "# TYPE banned gauge"); + assert_eq!( + lines[1], + "# HELP banned Whether the pool is currently banned from serving traffic (1 = banned, 0 = available)." + ); + assert_eq!(lines[2], "banned{database=\"app\",role=\"replica\"} 1"); + } } impl std::fmt::Display for Pools {