@@ -200,18 +200,17 @@ struct PrometheusMetric<Value: fmt::Display> {
200200
201201impl < Value : fmt:: Display > fmt:: Display for PrometheusMetric < Value > {
202202 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
203- let formatted_labels = self
204- . labels
203+ let mut sorted_labels: Vec < _ > = self . labels . iter ( ) . collect ( ) ;
204+ sorted_labels. sort_by_key ( |& ( key, _) | key) ;
205+ let formatted_labels = sorted_labels
205206 . iter ( )
206207 . map ( |( key, value) | format ! ( "{}=\" {}\" " , key, value) )
207208 . collect :: < Vec < _ > > ( )
208209 . join ( "," ) ;
209210 write ! (
210211 f,
211- "# HELP {name} {help} \n # TYPE {name} {ty} \n {name}{{{ formatted_labels}}} {value}\n " ,
212+ "{name}{{{ formatted_labels}}} {value}" ,
212213 name = format_args!( "pgcat_{}" , self . name) ,
213- help = self . help,
214- ty = self . ty,
215214 formatted_labels = formatted_labels,
216215 value = self . value
217216 )
@@ -247,7 +246,7 @@ impl<Value: fmt::Display> PrometheusMetric<Value> {
247246 labels. insert ( "pool" , address. pool_name . clone ( ) ) ;
248247 labels. insert ( "index" , address. address_index . to_string ( ) ) ;
249248 labels. insert ( "database" , address. database . to_string ( ) ) ;
250- labels. insert ( "user " , address. username . clone ( ) ) ;
249+ labels. insert ( "username " , address. username . clone ( ) ) ;
251250
252251 Self :: from_name ( & format ! ( "databases_{}" , name) , value, labels)
253252 }
@@ -264,7 +263,8 @@ impl<Value: fmt::Display> PrometheusMetric<Value> {
264263 labels. insert ( "pool" , address. pool_name . clone ( ) ) ;
265264 labels. insert ( "index" , address. address_index . to_string ( ) ) ;
266265 labels. insert ( "database" , address. database . to_string ( ) ) ;
267- labels. insert ( "user" , address. username . clone ( ) ) ;
266+ labels. insert ( "username" , address. username . clone ( ) ) ;
267+
268268 Self :: from_name ( & format ! ( "servers_{}" , name) , value, labels)
269269 }
270270
@@ -276,7 +276,7 @@ impl<Value: fmt::Display> PrometheusMetric<Value> {
276276 labels. insert ( "role" , address. role . to_string ( ) ) ;
277277 labels. insert ( "index" , address. address_index . to_string ( ) ) ;
278278 labels. insert ( "database" , address. database . to_string ( ) ) ;
279- labels. insert ( "user " , address. username . clone ( ) ) ;
279+ labels. insert ( "username " , address. username . clone ( ) ) ;
280280
281281 Self :: from_name ( & format ! ( "stats_{}" , name) , value, labels)
282282 }
@@ -288,6 +288,15 @@ impl<Value: fmt::Display> PrometheusMetric<Value> {
288288
289289 Self :: from_name ( & format ! ( "pools_{}" , name) , value, labels)
290290 }
291+
292+ fn get_header ( & self ) -> String {
293+ format ! (
294+ "\n # HELP {name} {help}\n # TYPE {name} {ty}" ,
295+ name = format_args!( "pgcat_{}" , self . name) ,
296+ help = self . help,
297+ ty = self . ty,
298+ )
299+ }
291300}
292301
293302async fn prometheus_stats (
@@ -313,6 +322,7 @@ async fn prometheus_stats(
313322
314323// Adds metrics shown in a SHOW STATS admin command.
315324fn push_address_stats ( lines : & mut Vec < String > ) {
325+ let mut grouped_metrics: HashMap < String , Vec < PrometheusMetric < u64 > > > = HashMap :: new ( ) ;
316326 for ( _, pool) in get_all_pools ( ) {
317327 for shard in 0 ..pool. shards ( ) {
318328 for server in 0 ..pool. servers ( shard) {
@@ -322,41 +332,64 @@ fn push_address_stats(lines: &mut Vec<String>) {
322332 if let Some ( prometheus_metric) =
323333 PrometheusMetric :: < u64 > :: from_address ( address, & key, value)
324334 {
325- lines. push ( prometheus_metric. to_string ( ) ) ;
335+ grouped_metrics
336+ . entry ( key)
337+ . or_default ( )
338+ . push ( prometheus_metric) ;
326339 } else {
327340 debug ! ( "Metric {} not implemented for {}" , key, address. name( ) ) ;
328341 }
329342 }
330343 }
331344 }
332345 }
346+ for ( _key, metrics) in grouped_metrics {
347+ if !metrics. is_empty ( ) {
348+ lines. push ( metrics[ 0 ] . get_header ( ) ) ;
349+ for metric in metrics {
350+ lines. push ( metric. to_string ( ) ) ;
351+ }
352+ }
353+ }
333354}
334355
335356// Adds relevant metrics shown in a SHOW POOLS admin command.
336357fn push_pool_stats ( lines : & mut Vec < String > ) {
358+ let mut grouped_metrics: HashMap < String , Vec < PrometheusMetric < u64 > > > = HashMap :: new ( ) ;
337359 let pool_stats = PoolStats :: construct_pool_lookup ( ) ;
338360 for ( pool_id, stats) in pool_stats. iter ( ) {
339361 for ( name, value) in stats. clone ( ) {
340362 if let Some ( prometheus_metric) =
341363 PrometheusMetric :: < u64 > :: from_pool ( pool_id. clone ( ) , & name, value)
342364 {
343- lines. push ( prometheus_metric. to_string ( ) ) ;
365+ grouped_metrics
366+ . entry ( name)
367+ . or_default ( )
368+ . push ( prometheus_metric) ;
344369 } else {
345370 debug ! ( "Metric {} not implemented for ({})" , name, * pool_id) ;
346371 }
347372 }
348373 }
374+ for ( _key, metrics) in grouped_metrics {
375+ if !metrics. is_empty ( ) {
376+ lines. push ( metrics[ 0 ] . get_header ( ) ) ;
377+ for metric in metrics {
378+ lines. push ( metric. to_string ( ) ) ;
379+ }
380+ }
381+ }
349382}
350383
351384// Adds relevant metrics shown in a SHOW DATABASES admin command.
352385fn push_database_stats ( lines : & mut Vec < String > ) {
386+ let mut grouped_metrics: HashMap < String , Vec < PrometheusMetric < u32 > > > = HashMap :: new ( ) ;
353387 for ( _, pool) in get_all_pools ( ) {
354388 let pool_config = pool. settings . clone ( ) ;
355389 for shard in 0 ..pool. shards ( ) {
356390 for server in 0 ..pool. servers ( shard) {
357391 let address = pool. address ( shard, server) ;
358392 let pool_state = pool. pool_state ( shard, server) ;
359-
360393 let metrics = vec ! [
361394 ( "pool_size" , pool_config. user. pool_size) ,
362395 ( "current_connections" , pool_state. connections) ,
@@ -365,14 +398,25 @@ fn push_database_stats(lines: &mut Vec<String>) {
365398 if let Some ( prometheus_metric) =
366399 PrometheusMetric :: < u32 > :: from_database_info ( address, key, value)
367400 {
368- lines. push ( prometheus_metric. to_string ( ) ) ;
401+ grouped_metrics
402+ . entry ( key. to_string ( ) )
403+ . or_default ( )
404+ . push ( prometheus_metric) ;
369405 } else {
370406 debug ! ( "Metric {} not implemented for {}" , key, address. name( ) ) ;
371407 }
372408 }
373409 }
374410 }
375411 }
412+ for ( _key, metrics) in grouped_metrics {
413+ if !metrics. is_empty ( ) {
414+ lines. push ( metrics[ 0 ] . get_header ( ) ) ;
415+ for metric in metrics {
416+ lines. push ( metric. to_string ( ) ) ;
417+ }
418+ }
419+ }
376420}
377421
378422// Adds relevant metrics shown in a SHOW SERVERS admin command.
@@ -405,7 +449,7 @@ fn push_server_stats(lines: &mut Vec<String>) {
405449 crate :: stats:: ServerState :: Idle => entry. idle_count += 1 ,
406450 }
407451 }
408-
452+ let mut grouped_metrics : HashMap < String , Vec < PrometheusMetric < u64 > > > = HashMap :: new ( ) ;
409453 for ( _, pool) in get_all_pools ( ) {
410454 for shard in 0 ..pool. shards ( ) {
411455 for server in 0 ..pool. servers ( shard) {
@@ -428,7 +472,10 @@ fn push_server_stats(lines: &mut Vec<String>) {
428472 if let Some ( prometheus_metric) =
429473 PrometheusMetric :: < u64 > :: from_server_info ( address, key, value)
430474 {
431- lines. push ( prometheus_metric. to_string ( ) ) ;
475+ grouped_metrics
476+ . entry ( key. to_string ( ) )
477+ . or_default ( )
478+ . push ( prometheus_metric) ;
432479 } else {
433480 debug ! ( "Metric {} not implemented for {}" , key, address. name( ) ) ;
434481 }
@@ -437,6 +484,14 @@ fn push_server_stats(lines: &mut Vec<String>) {
437484 }
438485 }
439486 }
487+ for ( _key, metrics) in grouped_metrics {
488+ if !metrics. is_empty ( ) {
489+ lines. push ( metrics[ 0 ] . get_header ( ) ) ;
490+ for metric in metrics {
491+ lines. push ( metric. to_string ( ) ) ;
492+ }
493+ }
494+ }
440495}
441496
442497pub async fn start_metric_server ( http_addr : SocketAddr ) {
0 commit comments