LCOV - code coverage report
Current view: top level - disco/metrics - fd_prometheus.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 73 156 46.8 %
Date: 2025-08-05 05:04:49 Functions: 6 11 54.5 %

          Line data    Source code
       1             : #include "fd_prometheus.h"
       2             : 
       3             : #include "fd_metrics.h"
       4             : 
       5             : #include "../topo/fd_topo.h"
       6             : #include "../../waltz/http/fd_http_server.h"
       7             : 
       8             : struct fd_prom_render {
       9             :   fd_http_server_t * http;
      10             :   ulong              last_name_hash;
      11             : };
      12             : 
      13             : typedef struct fd_prom_render fd_prom_render_t;
      14             : 
      15             : fd_prom_render_t
      16           3 : fd_prom_render_create( fd_http_server_t * http ) {
      17           3 :   return (fd_prom_render_t) {
      18           3 :     .http           = http,
      19           3 :     .last_name_hash = 0UL
      20           3 :   };
      21           3 : }
      22             : 
      23             : static void
      24             : render_header( fd_prom_render_t *        r,
      25         273 :                fd_metrics_meta_t const * metric ) {
      26             :   /* Only render header once per metric name */
      27         273 :   ulong hash = fd_cstr_hash( metric->name );
      28         273 :   if( r->last_name_hash != hash ) {
      29         141 :     if( r->last_name_hash ) {
      30         138 :       fd_http_server_printf( r->http, "\n" );
      31         138 :     }
      32         141 :     fd_http_server_printf( r->http, "# HELP %s %s\n# TYPE %s %s\n", metric->name, metric->desc, metric->name, fd_metrics_meta_type_str( metric ) );
      33         141 :     r->last_name_hash = hash;
      34         141 :   }
      35         273 : }
      36             : 
      37             : static void
      38             : render_link( fd_prom_render_t *        r,
      39             :              fd_metrics_meta_t const * metric,
      40             :              fd_topo_tile_t const *    tile,
      41             :              fd_topo_link_t const *    link,
      42           0 :              ulong                     value ) {
      43           0 :   render_header( r, metric );
      44           0 :   switch( metric->converter ) {
      45           0 :   case FD_METRICS_CONVERTER_NANOSECONDS:
      46           0 :     value = fd_metrics_convert_ticks_to_nanoseconds( value );
      47           0 :     break;
      48           0 :   case FD_METRICS_CONVERTER_NONE:
      49           0 :     break;
      50           0 :   default:
      51           0 :     FD_LOG_ERR(( "unknown converter %i", metric->converter ));
      52           0 :   }
      53           0 :   fd_http_server_printf( r->http, "%s{kind=\"%s\",kind_id=\"%lu\",link_kind=\"%s\",link_kind_id=\"%lu\"} %lu\n", metric->name, tile->name, tile->kind_id, link->name, link->kind_id, value );
      54           0 : }
      55             : 
      56             : static void
      57             : render_histogram( fd_prom_render_t *        r,
      58             :                   fd_metrics_meta_t const * metric,
      59           6 :                   fd_topo_tile_t const *    tile ) {
      60           6 :   render_header( r, metric );
      61             : 
      62           6 :   fd_histf_t hist[1];
      63           6 :   if( FD_LIKELY( metric->converter==FD_METRICS_CONVERTER_SECONDS ) )
      64           6 :     FD_TEST( fd_histf_new( hist, fd_metrics_convert_seconds_to_ticks( metric->histogram.seconds.min ), fd_metrics_convert_seconds_to_ticks ( metric->histogram.seconds.max ) ) );
      65           0 :   else if( FD_LIKELY( metric->converter==FD_METRICS_CONVERTER_NONE ) )
      66           0 :     FD_TEST( fd_histf_new( hist, metric->histogram.none.min, metric->histogram.none.max ) );
      67           0 :   else FD_LOG_ERR(( "unknown converter %i", metric->converter ));
      68             : 
      69           6 :   ulong value = 0;
      70           6 :   char value_str[ 64 ];
      71         102 :   for( ulong k=0; k<FD_HISTF_BUCKET_CNT; k++ ) {
      72          96 :     value += *(fd_metrics_tile( tile->metrics ) + metric->offset + k);
      73             : 
      74          96 :     char * le; /* le here means "less then or equal" not "left edge" */
      75          96 :     char le_str[ 64 ];
      76          96 :     if( FD_UNLIKELY( k==FD_HISTF_BUCKET_CNT-1UL ) ) le = "+Inf";
      77          90 :     else {
      78          90 :       ulong edge = fd_histf_right( hist, k );
      79          90 :       if( FD_LIKELY( metric->converter==FD_METRICS_CONVERTER_SECONDS ) ) {
      80          90 :         double edgef = fd_metrics_convert_ticks_to_seconds( edge-1 );
      81          90 :         FD_TEST( fd_cstr_printf_check( le_str, sizeof( le_str ), NULL, "%.17g", edgef ) );
      82          90 :       } else {
      83           0 :         FD_TEST( fd_cstr_printf_check( le_str, sizeof( le_str ), NULL, "%lu", edge-1 ) );
      84           0 :       }
      85          90 :       le = le_str;
      86          90 :     }
      87             : 
      88          96 :     FD_TEST( fd_cstr_printf_check( value_str, sizeof( value_str ), NULL, "%lu", value ));
      89          96 :     fd_http_server_printf( r->http, "%s_bucket{kind=\"%s\",kind_id=\"%lu\",le=\"%s\"} %s\n", metric->name, tile->name, tile->kind_id, le, value_str );
      90          96 :   }
      91             : 
      92           6 :   char sum_str[ 64 ];
      93           6 :   if( FD_LIKELY( metric->converter==FD_METRICS_CONVERTER_SECONDS ) ) {
      94           6 :     double sumf = fd_metrics_convert_ticks_to_seconds( *(fd_metrics_tile( tile->metrics ) + metric->offset + FD_HISTF_BUCKET_CNT) );
      95           6 :     FD_TEST( fd_cstr_printf_check( sum_str, sizeof( sum_str ), NULL, "%.17g", sumf ) );
      96           6 :   } else {
      97           0 :     FD_TEST( fd_cstr_printf_check( sum_str, sizeof( sum_str ), NULL, "%lu", *(fd_metrics_tile( tile->metrics ) + metric->offset + FD_HISTF_BUCKET_CNT) ));
      98           0 :   }
      99             : 
     100           6 :   fd_http_server_printf( r->http, "%s_sum{kind=\"%s\",kind_id=\"%lu\"} %s\n", metric->name, tile->name, tile->kind_id, sum_str );
     101           6 :   fd_http_server_printf( r->http, "%s_count{kind=\"%s\",kind_id=\"%lu\"} %s\n", metric->name, tile->name, tile->kind_id, value_str );
     102           6 : }
     103             : 
     104             : static void
     105             : render_counter( fd_prom_render_t *        r,
     106             :                 fd_metrics_meta_t const * metric,
     107         267 :                 fd_topo_tile_t const *    tile ) {
     108         267 :   render_header( r, metric );
     109         267 :   ulong value = *(fd_metrics_tile( tile->metrics ) + metric->offset);
     110             : 
     111         267 :   switch( metric->converter ) {
     112           0 :     case FD_METRICS_CONVERTER_NANOSECONDS:
     113           0 :       value = fd_metrics_convert_ticks_to_nanoseconds( value );
     114           0 :       break;
     115           0 :     case FD_METRICS_CONVERTER_SECONDS:
     116           0 :       value = (ulong)(fd_metrics_convert_ticks_to_seconds( value ) * 1e9);
     117           0 :       break;
     118         267 :     case FD_METRICS_CONVERTER_NONE:
     119         267 :       break;
     120           0 :     default:
     121           0 :       FD_LOG_ERR(( "unknown converter %i", metric->converter ));
     122         267 :   }
     123             : 
     124         267 :   fd_http_server_printf( r->http, "%s{kind=\"%s\",kind_id=\"%lu\"", metric->name, tile->name, tile->kind_id );
     125         267 :   if( metric->enum_name ) {
     126         156 :     fd_http_server_printf( r->http, ",%s=\"%s\"", metric->enum_name, metric->enum_variant );
     127         156 :   }
     128         267 :   fd_http_server_printf( r->http, "} %lu\n", value );
     129         267 : }
     130             : 
     131             : static void
     132             : render_links_in( fd_prom_render_t *        r,
     133             :                  fd_topo_t const *         topo,
     134             :                  ulong                     metrics_cnt,
     135           0 :                  fd_metrics_meta_t const * metrics ) {
     136           0 :   for( ulong i=0UL; i<metrics_cnt; i++ ) {
     137           0 :     fd_metrics_meta_t const * metric = &metrics[ i ];
     138           0 :     for( ulong j=0UL; j<topo->tile_cnt; j++ ) {
     139           0 :       fd_topo_tile_t const * tile = &topo->tiles[ j ];
     140           0 :       ulong polled_in_idx = 0UL;
     141           0 :       for( ulong k=0UL; k<tile->in_cnt; k++ ) {
     142           0 :         if( FD_UNLIKELY( !tile->in_link_poll[ k ] ) ) continue;
     143           0 :         fd_topo_link_t const * link = &topo->links[ tile->in_link_id[ k ] ];
     144           0 :         ulong value = *(fd_metrics_link_in( tile->metrics, polled_in_idx ) + metric->offset );
     145           0 :         render_link( r, metric, tile, link, value );
     146           0 :         polled_in_idx++;
     147           0 :       }
     148           0 :     }
     149           0 :   }
     150           0 : }
     151             : 
     152             : static void
     153             : render_links_out( fd_prom_render_t *        r,
     154             :                   fd_topo_t const *         topo,
     155             :                   ulong                     metrics_cnt,
     156           0 :                   fd_metrics_meta_t const * metrics ) {
     157           0 :   for( ulong i=0UL; i<metrics_cnt; i++ ) {
     158           0 :     fd_metrics_meta_t const * metric = &metrics[ i ];
     159           0 :     for( ulong j=0UL; j<topo->tile_cnt; j++ ) {
     160           0 :       fd_topo_tile_t const * tile = &topo->tiles[ j ];
     161           0 :       ulong reliable_conns_idx = 0UL;
     162           0 :       for( ulong k=0UL; k<topo->tile_cnt; k++ ) {
     163           0 :         fd_topo_tile_t const * consumer_tile = &topo->tiles[ k ];
     164           0 :         for( ulong l=0UL; l<consumer_tile->in_cnt; l++ ) {
     165           0 :           for( ulong m=0UL; m<tile->out_cnt; m++ ) {
     166           0 :             if( FD_UNLIKELY( consumer_tile->in_link_id[ l ]==tile->out_link_id[ m ] && consumer_tile->in_link_reliable[ l ] ) ) {
     167           0 :               fd_topo_link_t const * link = &topo->links[ consumer_tile->in_link_id[ l ] ];
     168           0 :               ulong value = *(fd_metrics_link_out( tile->metrics, reliable_conns_idx ) + metric->offset );
     169           0 :               render_link( r, metric, consumer_tile, link, value );
     170           0 :               reliable_conns_idx++;
     171           0 :             }
     172           0 :           }
     173           0 :         }
     174           0 :       }
     175           0 :     }
     176           0 :   }
     177           0 : }
     178             : 
     179             : static void
     180             : render_tile_metric( fd_prom_render_t *        r,
     181             :                     fd_topo_tile_t const *    tile,
     182         273 :                     fd_metrics_meta_t const * metric ) {
     183         273 :   if( FD_LIKELY( metric->type==FD_METRICS_TYPE_COUNTER || metric->type==FD_METRICS_TYPE_GAUGE ) ) {
     184         267 :     render_counter( r, metric, tile );
     185         267 :   } else if( FD_LIKELY( metric->type==FD_METRICS_TYPE_HISTOGRAM ) ) {
     186           6 :     render_histogram( r, metric, tile );
     187           6 :   }
     188         273 : }
     189             : 
     190             : static void
     191             : render_tile( fd_prom_render_t *        r,
     192             :              fd_topo_t const *         topo,
     193             :              char const *              tile_name,
     194             :              ulong                     metrics_cnt,
     195           0 :              fd_metrics_meta_t const * metrics ) {
     196           0 :   for( ulong i=0UL; i<metrics_cnt; i++ ) {
     197           0 :     for( ulong j=0UL; j<topo->tile_cnt; j++ ) {
     198             :       /* FIXME: This is O(n^2) rather than O(n). */
     199           0 :       if( FD_LIKELY( tile_name!=NULL && 0!=strcmp( topo->tiles[j].name, tile_name ) ) ) continue;
     200           0 :       render_tile_metric( r, topo->tiles+j, metrics+i );
     201           0 :     }
     202           0 :   }
     203           0 : }
     204             : 
     205             : void
     206             : fd_prometheus_render_tile( fd_http_server_t *        http,
     207             :                            fd_topo_tile_t const *    tile,
     208             :                            fd_metrics_meta_t const * metrics,
     209           3 :                            ulong                     metrics_cnt ) {
     210           3 :   fd_prom_render_t r = fd_prom_render_create( http );
     211         276 :   for( ulong i=0UL; i<metrics_cnt; i++ ) {
     212         273 :     render_tile_metric( &r, tile, metrics+i );
     213         273 :   }
     214           3 : }
     215             : 
     216             : void
     217             : fd_prometheus_render_all( fd_topo_t const *  topo,
     218           0 :                           fd_http_server_t * http ) {
     219           0 :   fd_prom_render_t r = fd_prom_render_create( http );
     220           0 :   render_tile( &r, topo, NULL, FD_METRICS_ALL_TOTAL, FD_METRICS_ALL );
     221           0 :   render_links_in( &r, topo, FD_METRICS_ALL_LINK_IN_TOTAL, FD_METRICS_ALL_LINK_IN );
     222           0 :   render_links_out( &r, topo, FD_METRICS_ALL_LINK_OUT_TOTAL, FD_METRICS_ALL_LINK_OUT );
     223           0 :   for( ulong i=0UL; i<FD_METRICS_TILE_KIND_CNT; i++ ) {
     224           0 :     render_tile( &r, topo, FD_METRICS_TILE_KIND_NAMES[ i ], FD_METRICS_TILE_KIND_SIZES[ i ], FD_METRICS_TILE_KIND_METRICS[ i ] );
     225           0 :   }
     226           0 : }

Generated by: LCOV version 1.14