LCOV - code coverage report
Current view: top level - source/common/stats - utility.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 1 2 50.0 %
Date: 2024-01-05 06:35:25 Functions: 1 2 50.0 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <string>
       4             : 
       5             : #include "envoy/stats/scope.h"
       6             : #include "envoy/stats/stats.h"
       7             : 
       8             : #include "source/common/common/thread.h"
       9             : #include "source/common/stats/symbol_table.h"
      10             : 
      11             : #include "absl/container/inlined_vector.h"
      12             : #include "absl/strings/string_view.h"
      13             : #include "absl/types/optional.h"
      14             : 
      15             : namespace Envoy {
      16             : namespace Stats {
      17             : 
      18             : /**
      19             :  * Represents a dynamically created stat name token based on absl::string_view.
      20             :  * This class wrapper is used in the 'Element' variant so that call-sites
      21             :  * can express explicit intent to create dynamic stat names, which are more
      22             :  * expensive than symbolic stat names. We use dynamic stat names only for
      23             :  * building stats based on names discovered in the line of a request.
      24             :  */
      25             : class DynamicName : public absl::string_view {
      26             : public:
      27             :   // This is intentionally left as an implicit conversion from string_view to
      28             :   // make call-sites easier to read, e.g.
      29             :   //    Utility::counterFromElements(*scope, {DynamicName("a"), DynamicName("b")});
      30        4805 :   explicit DynamicName(absl::string_view str) : absl::string_view(str) {}
      31             : };
      32             : 
      33             : /**
      34             :  * Represents a dynamically created stat name token based on std::string.
      35             :  * This class wrapper is used in the 'Element' variant so that call-sites
      36             :  * can express explicit intent to create dynamic stat names, which are more
      37             :  * expensive than symbolic stat names. We use dynamic stat names only for
      38             :  * building stats based on names discovered in the line of a request.
      39             :  *
      40             :  * Specifically, this class should be used only when the content of the string
      41             :  * can be changed between the object creation and usage.
      42             :  */
      43             : class DynamicSavedName : public std::string {
      44             : public:
      45             :   // This is intentionally left as an implicit conversion from string_view to
      46             :   // make call-sites easier to read, e.g.
      47             :   //    Utility::counterFromElements(*scope, {DynamicSavedName("a"), DynamicSavedName("b")});
      48           0 :   explicit DynamicSavedName(absl::string_view str) : std::string(str.begin(), str.end()) {}
      49             : };
      50             : 
      51             : /**
      52             :  * Holds either a symbolic StatName or a dynamic string, for the purpose of
      53             :  * composing a vector to pass to Utility::counterFromElements, etc. This is
      54             :  * a programming convenience to create joined stat names. It is easier to
      55             :  * call the above helpers than to use SymbolTable::join(), because the helpers
      56             :  * hide the memory management of the joined storage, and they allow easier
      57             :  * co-mingling of symbolic and dynamic stat-name components.
      58             :  */
      59             : using Element = absl::variant<StatName, DynamicName, DynamicSavedName>;
      60             : using ElementVec = absl::InlinedVector<Element, 8>;
      61             : 
      62             : /**
      63             :  * Common stats utility routines.
      64             :  */
      65             : namespace Utility {
      66             : /**
      67             :  * ':' is a reserved char in statsd. Do a character replacement to avoid
      68             :  * costly inline translations later.
      69             :  *
      70             :  * @param name the stat name to sanitize.
      71             :  * @return the sanitized stat name.
      72             :  */
      73             : std::string sanitizeStatsName(absl::string_view name);
      74             : 
      75             : /**
      76             :  * Finds a metric tag with the specified name.
      77             :  *
      78             :  * @param metric The metric in which the tag is expected to exist.
      79             :  * @param find_tag_name The name of the tag to search for.
      80             :  * @return The value of the tag, if found.
      81             :  */
      82             : absl::optional<StatName> findTag(const Metric& metric, StatName find_tag_name);
      83             : 
      84             : /**
      85             :  * Creates a nested scope from a vector of StatNames which are used to create the
      86             :  * name.
      87             :  *
      88             :  * See also scopeFromElements, which is slightly slower but allows
      89             :  * passing DynamicName(string)s as names.
      90             :  *
      91             :  * @param scope The scope in which to create the counter.
      92             :  * @param elements The vector of mixed DynamicName and StatName
      93             :  * @return A scope named using the joined elements.
      94             :  */
      95             : ScopeSharedPtr scopeFromStatNames(Scope& scope, const StatNameVec& names);
      96             : 
      97             : /**
      98             :  * Creates a counter from a vector of tokens which are used to create the
      99             :  * name. The tokens can be specified as DynamicName or StatName. For
     100             :  * tokens specified as DynamicName, a dynamic StatName will be created. See
     101             :  * https://github.com/envoyproxy/envoy/blob/main/source/docs/stats.md#dynamic-stat-tokens
     102             :  * for more detail on why symbolic StatNames are preferred when possible.
     103             :  *
     104             :  * See also counterFromStatNames, which is slightly faster but does not allow
     105             :  * passing DynamicName(string)s as names.
     106             :  *
     107             :  * @param scope The scope in which to create the counter.
     108             :  * @param elements The vector of mixed DynamicName and StatName
     109             :  * @param tags optionally specified tags.
     110             :  * @return A counter named using the joined elements.
     111             :  */
     112             : Counter& counterFromElements(Scope& scope, const ElementVec& elements,
     113             :                              StatNameTagVectorOptConstRef tags = absl::nullopt);
     114             : 
     115             : /**
     116             :  * Creates a counter from a vector of tokens which are used to create the
     117             :  * name. The tokens must be of type StatName.
     118             :  *
     119             :  * See also counterFromElements, which is slightly slower, but allows
     120             :  * passing DynamicName(string)s as elements.
     121             :  *
     122             :  * @param scope The scope in which to create the counter.
     123             :  * @param names The vector of StatNames
     124             :  * @param tags optionally specified tags.
     125             :  * @return A counter named using the joined elements.
     126             :  */
     127             : Counter& counterFromStatNames(Scope& scope, const StatNameVec& names,
     128             :                               StatNameTagVectorOptConstRef tags = absl::nullopt);
     129             : 
     130             : /**
     131             :  * Creates a gauge from a vector of tokens which are used to create the
     132             :  * name. The tokens can be specified as DynamicName or StatName. For
     133             :  * tokens specified as DynamicName, a dynamic StatName will be created. See
     134             :  * https://github.com/envoyproxy/envoy/blob/main/source/docs/stats.md#dynamic-stat-tokens
     135             :  * for more detail on why symbolic StatNames are preferred when possible.
     136             :  *
     137             :  * See also gaugeFromStatNames, which is slightly faster but does not allow
     138             :  * passing DynamicName(string)s as names.
     139             :  *
     140             :  * @param scope The scope in which to create the counter.
     141             :  * @param elements The vector of mixed DynamicName and StatName
     142             :  * @param import_mode Whether hot-restart should accumulate this value.
     143             :  * @param tags optionally specified tags.
     144             :  * @return A gauge named using the joined elements.
     145             :  */
     146             : Gauge& gaugeFromElements(Scope& scope, const ElementVec& elements, Gauge::ImportMode import_mode,
     147             :                          StatNameTagVectorOptConstRef tags = absl::nullopt);
     148             : 
     149             : /**
     150             :  * Creates a gauge from a vector of tokens which are used to create the
     151             :  * name. The tokens must be of type StatName.
     152             :  *
     153             :  * See also gaugeFromElements, which is slightly slower, but allows
     154             :  * passing DynamicName(string)s as elements.
     155             :  *
     156             :  * @param scope The scope in which to create the counter.
     157             :  * @param names The vector of StatNames
     158             :  * @param import_mode Whether hot-restart should accumulate this value.
     159             :  * @param tags optionally specified tags.
     160             :  * @return A gauge named using the joined elements.
     161             :  */
     162             : Gauge& gaugeFromStatNames(Scope& scope, const StatNameVec& elements, Gauge::ImportMode import_mode,
     163             :                           StatNameTagVectorOptConstRef tags = absl::nullopt);
     164             : 
     165             : /**
     166             :  * Creates a histogram from a vector of tokens which are used to create the
     167             :  * name. The tokens can be specified as DynamicName or StatName. For
     168             :  * tokens specified as DynamicName, a dynamic StatName will be created. See
     169             :  * https://github.com/envoyproxy/envoy/blob/main/source/docs/stats.md#dynamic-stat-tokens
     170             :  * for more detail on why symbolic StatNames are preferred when possible.
     171             :  *
     172             :  * See also histogramFromStatNames, which is slightly faster but does not allow
     173             :  * passing DynamicName(string)s as names.
     174             :  *
     175             :  * @param scope The scope in which to create the counter.
     176             :  * @param elements The vector of mixed DynamicName and StatName
     177             :  * @param unit The unit of measurement.
     178             :  * @param tags optionally specified tags.
     179             :  * @return A histogram named using the joined elements.
     180             :  */
     181             : Histogram& histogramFromElements(Scope& scope, const ElementVec& elements, Histogram::Unit unit,
     182             :                                  StatNameTagVectorOptConstRef tags = absl::nullopt);
     183             : 
     184             : /**
     185             :  * Creates a histogram from a vector of tokens which are used to create the
     186             :  * name. The tokens must be of type StatName.
     187             :  *
     188             :  * See also histogramFromElements, which is slightly slower, but allows
     189             :  * passing DynamicName(string)s as elements.
     190             :  *
     191             :  * @param scope The scope in which to create the counter.
     192             :  * @param elements The vector of mixed DynamicName and StatName
     193             :  * @param unit The unit of measurement.
     194             :  * @param tags optionally specified tags.
     195             :  * @return A histogram named using the joined elements.
     196             :  */
     197             : Histogram& histogramFromStatNames(Scope& scope, const StatNameVec& elements, Histogram::Unit unit,
     198             :                                   StatNameTagVectorOptConstRef tags = absl::nullopt);
     199             : 
     200             : /**
     201             :  * Creates a TextReadout from a vector of tokens which are used to create the
     202             :  * name. The tokens can be specified as DynamicName or StatName. For
     203             :  * tokens specified as DynamicName, a dynamic StatName will be created. See
     204             :  * https://github.com/envoyproxy/envoy/blob/main/source/docs/stats.md#dynamic-stat-tokens
     205             :  * for more detail on why symbolic StatNames are preferred when possible.
     206             :  *
     207             :  * See also TextReadoutFromStatNames, which is slightly faster but does not allow
     208             :  * passing DynamicName(string)s as names.
     209             :  *
     210             :  * @param scope The scope in which to create the counter.
     211             :  * @param elements The vector of mixed DynamicName and StatName
     212             :  * @param unit The unit of measurement.
     213             :  * @param tags optionally specified tags.
     214             :  * @return A TextReadout named using the joined elements.
     215             :  */
     216             : TextReadout& textReadoutFromElements(Scope& scope, const ElementVec& elements,
     217             :                                      StatNameTagVectorOptConstRef tags = absl::nullopt);
     218             : 
     219             : /**
     220             :  * Creates a TextReadout from a vector of tokens which are used to create the
     221             :  * name. The tokens must be of type StatName.
     222             :  *
     223             :  * See also TextReadoutFromElements, which is slightly slower, but allows
     224             :  * passing DynamicName(string)s as elements.
     225             :  *
     226             :  * @param scope The scope in which to create the counter.
     227             :  * @param elements The vector of mixed DynamicName and StatName
     228             :  * @param unit The unit of measurement.
     229             :  * @param tags optionally specified tags.
     230             :  * @return A TextReadout named using the joined elements.
     231             :  */
     232             : TextReadout& textReadoutFromStatNames(Scope& scope, const StatNameVec& elements,
     233             :                                       StatNameTagVectorOptConstRef tags = absl::nullopt);
     234             : 
     235             : } // namespace Utility
     236             : 
     237             : /**
     238             :  * Holds a reference to a stat by name. Note that the stat may not be created
     239             :  * yet at the time CachedReference is created. Calling get() then does a lazy
     240             :  * lookup, potentially returning absl::nullopt if the stat doesn't exist yet.
     241             :  * StatReference works whether the name was constructed symbolically, or with
     242             :  * StatNameDynamicStorage.
     243             :  *
     244             :  * Lookups are very slow, taking time proportional to the size of the scope,
     245             :  * holding mutexes during the lookup. However once the lookup succeeds, the
     246             :  * result is cached atomically, and further calls to get() are thus fast and
     247             :  * mutex-free. The implementation may be faster for stats that are named
     248             :  * symbolically.
     249             :  *
     250             :  * CachedReference is valid for the lifetime of the Scope. When the Scope
     251             :  * becomes invalid, CachedReferences must also be dropped as they will hold
     252             :  * pointers into the scope.
     253             :  */
     254             : template <class StatType> class CachedReference {
     255             : public:
     256             :   CachedReference(Scope& scope, absl::string_view name) : scope_(scope), name_(std::string(name)) {}
     257             : 
     258             :   /**
     259             :    * Finds the named stat, if it exists, returning it as an optional.
     260             :    */
     261             :   absl::optional<std::reference_wrapper<StatType>> get() {
     262             :     StatType* stat = stat_.get([this]() -> StatType* {
     263             :       StatType* stat = nullptr;
     264             :       IterateFn<StatType> check_stat = [this,
     265             :                                         &stat](const RefcountPtr<StatType>& shared_stat) -> bool {
     266             :         if (shared_stat->name() == name_) {
     267             :           stat = shared_stat.get();
     268             :           return false; // Stop iteration.
     269             :         }
     270             :         return true;
     271             :       };
     272             :       scope_.iterate(check_stat);
     273             :       return stat;
     274             :     });
     275             :     if (stat == nullptr) {
     276             :       return absl::nullopt;
     277             :     }
     278             :     return *stat;
     279             :   }
     280             : 
     281             : private:
     282             :   Scope& scope_;
     283             :   const std::string name_;
     284             :   Thread::AtomicPtr<StatType, Thread::AtomicPtrAllocMode::DoNotDelete> stat_;
     285             : };
     286             : 
     287             : } // namespace Stats
     288             : } // namespace Envoy

Generated by: LCOV version 1.15