LCOV - code coverage report
Current view: top level - envoy/stats - stats_macros.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 17 18 94.4 %
Date: 2024-01-05 06:35:25 Functions: 65 717 9.1 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <string>
       4             : 
       5             : #include "envoy/stats/histogram.h"
       6             : #include "envoy/stats/stats.h"
       7             : 
       8             : #include "source/common/stats/symbol_table.h"
       9             : #include "source/common/stats/utility.h"
      10             : 
      11             : #include "absl/strings/match.h"
      12             : #include "absl/strings/str_cat.h"
      13             : 
      14             : namespace Envoy {
      15             : /**
      16             :  * These are helper macros for allocating "fixed" stats throughout the code base in a way that
      17             :  * is also easy to mock and test. The general flow looks like this:
      18             :  *
      19             :  * Define a block of stats like this:
      20             :  *   #define MY_COOL_STATS(COUNTER, GAUGE, HISTOGRAM)     \
      21             :  *     COUNTER(counter1)                                  \
      22             :  *     GAUGE(gauge1, mode)                                \
      23             :  *     HISTOGRAM(histogram1, unit)
      24             :  *     ...
      25             :  *
      26             :  * By convention, starting with #7083, we sort the lines of this macro block, so
      27             :  * all the counters are grouped together, then all the gauges, etc. We do not
      28             :  * use clang-format-on/off etc. "bazel run //tools/code_format:check_format -- fix" will take
      29             :  * care of lining up the backslashes.
      30             :  *
      31             :  * Now actually put these stats somewhere, usually as a member of a struct:
      32             :  *   struct MyCoolStats {
      33             :  *     MY_COOL_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT, GENERATE_HISTOGRAM_STRUCT)
      34             :  *   };
      35             :  *
      36             :  * Finally, when you want to actually instantiate the above struct using a Stats::Pool, you do:
      37             :  *   MyCoolStats stats{
      38             :  *     MY_COOL_STATS(POOL_COUNTER(...), POOL_GAUGE(...), POOL_HISTOGRAM(...))};
      39             :  *
      40             :  *
      41             :  * The above constructs are the simplest way to declare counters, gauges,
      42             :  * histograms, and text-readouts in your data structures. However they incur
      43             :  * some overhead to symbolize the names every time they are instantiated. For
      44             :  * data structures that are re-instantiated extensively during operation,
      45             :  * e.g. in response to an xDS update, We can separately instantiate a
      46             :  * StatNameStruct, containing symbolized names for each stat. That should be
      47             :  * instantiated once at startup and held in some context or factory. Do that
      48             :  * with:
      49             :  *
      50             :  *    MAKE_STAT_NAMES_STRUCT(MyStatNames, MY_COOL_STATS);
      51             :  *
      52             :  * This generates a structure definition with a constructor that requires a
      53             :  * SymbolTable. So you must, in a context instantiated once, initialize with:
      54             :  *
      55             :  *    : my_cool_stat_names_(stat_store.symbolTable())
      56             :  *
      57             :  * Once you have the StatNamesStruct instance declared, you can create a stats
      58             :  * struct efficiently during operation (e.g. in an xDS handler) with
      59             :  *
      60             :  *    MAKE_STATS_STRUCT(MyStats, MyStatNames, MY_COOL_STATS);
      61             :  *
      62             :  * This new structure is constructed with 2 or 3 args:
      63             :  *    1. The stat_names struct created from MAKE_STAT_NAMES_STRUCT
      64             :  *    2. The scope in which to instantiate the stats
      65             :  *    3. An optional prefix, which will be prepended to each stat name.
      66             :  * For example:
      67             :  *
      68             :  *    : my_cool_stats_(context.my_cool_stat_names_, scope, opt_prefix)
      69             :  */
      70             : 
      71             : // Fully-qualified for use in external callsites.
      72             : #define GENERATE_COUNTER_STRUCT(NAME) Envoy::Stats::Counter& NAME##_;
      73             : #define GENERATE_GAUGE_STRUCT(NAME, MODE) Envoy::Stats::Gauge& NAME##_;
      74             : #define GENERATE_HISTOGRAM_STRUCT(NAME, UNIT) Envoy::Stats::Histogram& NAME##_;
      75             : #define GENERATE_TEXT_READOUT_STRUCT(NAME) Envoy::Stats::TextReadout& NAME##_;
      76             : 
      77       84762 : #define FINISH_STAT_DECL_(X) #X)),
      78       21148 : #define FINISH_STAT_DECL_MODE_(X, MODE) #X), Envoy::Stats::Gauge::ImportMode::MODE),
      79         892 : #define FINISH_STAT_DECL_UNIT_(X, UNIT) #X), Envoy::Stats::Histogram::Unit::UNIT),
      80             : 
      81      125540 : static inline std::string statPrefixJoin(absl::string_view prefix, absl::string_view token) {
      82      125540 :   if (prefix.empty()) {
      83       15033 :     return std::string(token);
      84      115319 :   } else if (absl::EndsWith(prefix, ".")) {
      85             :     // TODO(jmarantz): eliminate this case -- remove all the trailing dots from prefixes.
      86       89380 :     return absl::StrCat(prefix, token);
      87       89380 :   }
      88       21127 :   return absl::StrCat(prefix, ".", token);
      89      125540 : }
      90             : 
      91       84528 : #define POOL_COUNTER_PREFIX(POOL, PREFIX) (POOL).counterFromString(Envoy::statPrefixJoin(PREFIX, FINISH_STAT_DECL_
      92       21148 : #define POOL_GAUGE_PREFIX(POOL, PREFIX) (POOL).gaugeFromString(Envoy::statPrefixJoin(PREFIX, FINISH_STAT_DECL_MODE_
      93         892 : #define POOL_HISTOGRAM_PREFIX(POOL, PREFIX) (POOL).histogramFromString(Envoy::statPrefixJoin(PREFIX, FINISH_STAT_DECL_UNIT_
      94         234 : #define POOL_TEXT_READOUT_PREFIX(POOL, PREFIX) (POOL).textReadoutFromString(Envoy::statPrefixJoin(PREFIX, FINISH_STAT_DECL_
      95             : #define POOL_STAT_NAME_PREFIX(POOL, PREFIX) (POOL).symbolTable().textReadoutFromString(Envoy::statPrefixJoin(PREFIX, FINISH_STAT_DECL_
      96             : 
      97             : #define POOL_COUNTER(POOL) POOL_COUNTER_PREFIX(POOL, "")
      98             : #define POOL_GAUGE(POOL) POOL_GAUGE_PREFIX(POOL, "")
      99             : #define POOL_HISTOGRAM(POOL) POOL_HISTOGRAM_PREFIX(POOL, "")
     100             : #define POOL_TEXT_READOUT(POOL) POOL_TEXT_READOUT_PREFIX(POOL, "")
     101             : 
     102             : #define NULL_STAT_DECL_(X) std::string(#X)),
     103             : #define NULL_STAT_DECL_IGNORE_MODE_(X, MODE) std::string(#X)),
     104             : 
     105             : #define NULL_POOL_GAUGE(POOL) (POOL).nullGauge(NULL_STAT_DECL_IGNORE_MODE_
     106             : 
     107             : // Used for declaring StatNames in a structure.
     108             : #define GENERATE_STAT_NAME_STRUCT(NAME, ...) Envoy::Stats::StatName NAME##_;
     109             : #define GENERATE_STAT_NAME_INIT(NAME, ...) , NAME##_(pool_.add(#NAME))
     110             : 
     111             : // Used for defining constrcutors of stat objects
     112             : #define GENERATE_CONSTRUCTOR_PARAM(NAME) Envoy::Stats::Counter &NAME,
     113             : #define GENERATE_CONSTRUCTOR_COUNTER_PARAM(NAME) Envoy::Stats::Counter &NAME,
     114             : #define GENERATE_CONSTRUCTOR_GAUGE_PARAM(NAME, ...) Envoy::Stats::Gauge &NAME,
     115             : #define GENERATE_CONSTRUCTOR_INIT_LIST(NAME, ...) , NAME##_(NAME)
     116             : 
     117             : // Macros for declaring stat-structures using StatNames, for those that must be
     118             : // instantiated during operation, and where speed and scale matters. These
     119             : // macros are not for direct use; they are only for use from
     120             : // MAKE_STAT_NAMES_STRUCT. and MAKE_STAT_STRUCT.
     121             : #define MAKE_STATS_STRUCT_COUNTER_HELPER_(NAME)                                                    \
     122             :   , NAME##_(Envoy::Stats::Utility::counterFromStatNames(scope, {prefix, stat_names.NAME##_}))
     123             : #define MAKE_STATS_STRUCT_GAUGE_HELPER_(NAME, MODE)                                                \
     124             :   , NAME##_(Envoy::Stats::Utility::gaugeFromStatNames(scope, {prefix, stat_names.NAME##_},         \
     125             :                                                       Envoy::Stats::Gauge::ImportMode::MODE))
     126             : #define MAKE_STATS_STRUCT_HISTOGRAM_HELPER_(NAME, UNIT)                                            \
     127             :   , NAME##_(Envoy::Stats::Utility::histogramFromStatNames(scope, {prefix, stat_names.NAME##_},     \
     128             :                                                           Envoy::Stats::Histogram::Unit::UNIT))
     129             : #define MAKE_STATS_STRUCT_TEXT_READOUT_HELPER_(NAME)                                               \
     130             :   , NAME##_(Envoy::Stats::Utility::textReadoutFromStatNames(scope, {prefix, stat_names.NAME##_}))
     131             : 
     132             : #define MAKE_STATS_STRUCT_STATNAME_HELPER_(name)
     133             : #define GENERATE_STATNAME_STRUCT(name)
     134             : 
     135             : /**
     136             :  * Generates a struct with StatNames for a subsystem, based on the stats macro
     137             :  * with COUNTER, GAUGE, HISTOGRAM, TEXT_READOUT, and STATNAME calls. The
     138             :  * ALL_STATS macro must have all 5 parameters.
     139             :  */
     140             : #define MAKE_STAT_NAMES_STRUCT(StatNamesStruct, ALL_STATS)                                         \
     141             :   struct StatNamesStruct {                                                                         \
     142             :     explicit StatNamesStruct(Envoy::Stats::SymbolTable& symbol_table)                              \
     143             :         : pool_(symbol_table)                                                                      \
     144             :               ALL_STATS(GENERATE_STAT_NAME_INIT, GENERATE_STAT_NAME_INIT, GENERATE_STAT_NAME_INIT, \
     145       22157 :                         GENERATE_STAT_NAME_INIT, GENERATE_STAT_NAME_INIT) {}                       \
     146             :     Envoy::Stats::StatNamePool pool_;                                                              \
     147             :     ALL_STATS(GENERATE_STAT_NAME_STRUCT, GENERATE_STAT_NAME_STRUCT, GENERATE_STAT_NAME_STRUCT,     \
     148             :               GENERATE_STAT_NAME_STRUCT, GENERATE_STAT_NAME_STRUCT)                                \
     149             :   }
     150             : 
     151             : /**
     152             :  * Instantiates a structure of stats based on a new scope and optional prefix,
     153             :  * using a predefined structure of stat names. A reference to the stat_names is
     154             :  * also stored in the structure, for two reasons: (a) as a syntactic convenience
     155             :  * for using macros to generate the comma separators for the initializer and (b)
     156             :  * as a convenience at the call-site to access STATNAME-declared names from the
     157             :  * stats structure.
     158             :  */
     159             : #define MAKE_STATS_STRUCT(StatsStruct, StatNamesStruct, ALL_STATS)                                 \
     160             :   struct StatsStruct {                                                                             \
     161             :     /* Also referenced in Stats::createDeferredCompatibleStats. */                                 \
     162             :     using StatNameType = StatNamesStruct;                                                          \
     163           0 :     static const absl::string_view typeName() { return #StatsStruct; }                             \
     164             :     StatsStruct(const StatNamesStruct& stat_names, Envoy::Stats::Scope& scope,                     \
     165             :                 Envoy::Stats::StatName prefix = Envoy::Stats::StatName())                          \
     166             :         : stat_names_(stat_names)                                                                  \
     167             :               ALL_STATS(MAKE_STATS_STRUCT_COUNTER_HELPER_, MAKE_STATS_STRUCT_GAUGE_HELPER_,        \
     168             :                         MAKE_STATS_STRUCT_HISTOGRAM_HELPER_,                                       \
     169             :                         MAKE_STATS_STRUCT_TEXT_READOUT_HELPER_,                                    \
     170       17111 :                         MAKE_STATS_STRUCT_STATNAME_HELPER_) {}                                     \
     171             :     const StatNameType& stat_names_;                                                               \
     172             :     ALL_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT, GENERATE_HISTOGRAM_STRUCT,           \
     173             :               GENERATE_TEXT_READOUT_STRUCT, GENERATE_STATNAME_STRUCT)                              \
     174             :   }
     175             : } // namespace Envoy

Generated by: LCOV version 1.15