diff --git a/source/common/grpc/BUILD b/source/common/grpc/BUILD index e49c1c1db0162..8534b6f0c67c0 100644 --- a/source/common/grpc/BUILD +++ b/source/common/grpc/BUILD @@ -115,6 +115,7 @@ envoy_cc_library( "//include/envoy/stats:stats_interface", "//source/common/common:hash_lib", "//source/common/stats:symbol_table_lib", + "//source/common/stats:utility_lib", ], ) diff --git a/source/common/grpc/context_impl.cc b/source/common/grpc/context_impl.cc index f612f71cc0740..4c0e2f91ebc3e 100644 --- a/source/common/grpc/context_impl.cc +++ b/source/common/grpc/context_impl.cc @@ -4,48 +4,29 @@ #include #include "common/grpc/common.h" +#include "common/stats/utility.h" namespace Envoy { namespace Grpc { ContextImpl::ContextImpl(Stats::SymbolTable& symbol_table) - : symbol_table_(symbol_table), stat_name_pool_(symbol_table), - grpc_(stat_name_pool_.add("grpc")), grpc_web_(stat_name_pool_.add("grpc-web")), - success_(stat_name_pool_.add("success")), failure_(stat_name_pool_.add("failure")), - total_(stat_name_pool_.add("total")), zero_(stat_name_pool_.add("0")), + : stat_name_pool_(symbol_table), grpc_(stat_name_pool_.add("grpc")), + grpc_web_(stat_name_pool_.add("grpc-web")), success_(stat_name_pool_.add("success")), + failure_(stat_name_pool_.add("failure")), total_(stat_name_pool_.add("total")), + zero_(stat_name_pool_.add("0")), request_message_count_(stat_name_pool_.add("request_message_count")), response_message_count_(stat_name_pool_.add("response_message_count")), upstream_rq_time_(stat_name_pool_.add("upstream_rq_time")), stat_names_(symbol_table) {} -// Makes a stat name from a string, if we don't already have one for it. -// This always takes a lock on mutex_, and if we haven't seen the name -// before, it also takes a lock on the symbol table. -// -// TODO(jmarantz): See https://github.com/envoyproxy/envoy/pull/7008 for -// a lock-free approach to creating dynamic stat-names based on requests. -Stats::StatName ContextImpl::makeDynamicStatName(absl::string_view name) { - Thread::LockGuard lock(mutex_); - auto iter = stat_name_map_.find(name); - if (iter != stat_name_map_.end()) { - return iter->second; - } - const Stats::StatName stat_name = stat_name_pool_.add(name); - stat_name_map_[std::string(name)] = stat_name; - return stat_name; -} - // Gets the stat prefix and underlying storage, depending on whether request_names is empty -std::pair -ContextImpl::getPrefix(Protocol protocol, const absl::optional& request_names) { +Stats::ElementVec ContextImpl::statElements(Protocol protocol, + const absl::optional& request_names, + Stats::Element suffix) { const Stats::StatName protocolName = protocolStatName(protocol); if (request_names) { - Stats::SymbolTable::StoragePtr prefix_storage = - symbol_table_.join({protocolName, request_names->service_, request_names->method_}); - Stats::StatName prefix = Stats::StatName(prefix_storage.get()); - return {prefix, std::move(prefix_storage)}; - } else { - return {protocolName, nullptr}; + return Stats::ElementVec{protocolName, request_names->service_, request_names->method_, suffix}; } + return Stats::ElementVec{protocolName, suffix}; } void ContextImpl::chargeStat(const Upstream::ClusterInfo& cluster, Protocol protocol, @@ -57,28 +38,20 @@ void ContextImpl::chargeStat(const Upstream::ClusterInfo& cluster, Protocol prot absl::string_view status_str = grpc_status->value().getStringView(); auto iter = stat_names_.status_names_.find(status_str); - const Stats::StatName status_stat_name = - (iter != stat_names_.status_names_.end()) ? iter->second : makeDynamicStatName(status_str); - const Stats::SymbolTable::StoragePtr stat_name_storage = - request_names ? symbol_table_.join({protocolStatName(protocol), request_names->service_, - request_names->method_, status_stat_name}) - : symbol_table_.join({protocolStatName(protocol), status_stat_name}); - - cluster.statsScope().counterFromStatName(Stats::StatName(stat_name_storage.get())).inc(); + Stats::ElementVec elements = + statElements(protocol, request_names, + (iter != stat_names_.status_names_.end()) ? Stats::Element(iter->second) + : Stats::DynamicName(status_str)); + Stats::Utility::counterFromElements(cluster.statsScope(), elements).inc(); chargeStat(cluster, protocol, request_names, (status_str == "0")); } void ContextImpl::chargeStat(const Upstream::ClusterInfo& cluster, Protocol protocol, const absl::optional& request_names, bool success) { - auto prefix_and_storage = getPrefix(protocol, request_names); - Stats::StatName prefix = prefix_and_storage.first; - - const Stats::SymbolTable::StoragePtr status = - symbol_table_.join({prefix, successStatName(success)}); - const Stats::SymbolTable::StoragePtr total = symbol_table_.join({prefix, total_}); - - cluster.statsScope().counterFromStatName(Stats::StatName(status.get())).inc(); - cluster.statsScope().counterFromStatName(Stats::StatName(total.get())).inc(); + Stats::ElementVec elements = statElements(protocol, request_names, successStatName(success)); + Stats::Utility::counterFromElements(cluster.statsScope(), elements).inc(); + elements.back() = total_; + Stats::Utility::counterFromElements(cluster.statsScope(), elements).inc(); } void ContextImpl::chargeStat(const Upstream::ClusterInfo& cluster, @@ -89,43 +62,23 @@ void ContextImpl::chargeStat(const Upstream::ClusterInfo& cluster, void ContextImpl::chargeRequestMessageStat(const Upstream::ClusterInfo& cluster, const absl::optional& request_names, uint64_t amount) { - auto prefix_and_storage = getPrefix(Protocol::Grpc, request_names); - Stats::StatName prefix = prefix_and_storage.first; - - const Stats::SymbolTable::StoragePtr request_message_count = - symbol_table_.join({prefix, request_message_count_}); - - cluster.statsScope() - .counterFromStatName(Stats::StatName(request_message_count.get())) - .add(amount); + Stats::ElementVec elements = statElements(Protocol::Grpc, request_names, request_message_count_); + Stats::Utility::counterFromElements(cluster.statsScope(), elements).add(amount); } void ContextImpl::chargeResponseMessageStat(const Upstream::ClusterInfo& cluster, const absl::optional& request_names, uint64_t amount) { - auto prefix_and_storage = getPrefix(Protocol::Grpc, request_names); - Stats::StatName prefix = prefix_and_storage.first; - - const Stats::SymbolTable::StoragePtr response_message_count = - symbol_table_.join({prefix, response_message_count_}); - - cluster.statsScope() - .counterFromStatName(Stats::StatName(response_message_count.get())) - .add(amount); + Stats::ElementVec elements = statElements(Protocol::Grpc, request_names, response_message_count_); + Stats::Utility::counterFromElements(cluster.statsScope(), elements).add(amount); } void ContextImpl::chargeUpstreamStat(const Upstream::ClusterInfo& cluster, const absl::optional& request_names, std::chrono::milliseconds duration) { - auto prefix_and_storage = getPrefix(Protocol::Grpc, request_names); - Stats::StatName prefix = prefix_and_storage.first; - - const Stats::SymbolTable::StoragePtr upstream_rq_time = - symbol_table_.join({prefix, upstream_rq_time_}); - - cluster.statsScope() - .histogramFromStatName(Stats::StatName(upstream_rq_time.get()), - Stats::Histogram::Unit::Milliseconds) + Stats::ElementVec elements = statElements(Protocol::Grpc, request_names, upstream_rq_time_); + Stats::Utility::histogramFromElements(cluster.statsScope(), elements, + Stats::Histogram::Unit::Milliseconds) .recordValue(duration.count()); } @@ -136,8 +89,8 @@ ContextImpl::resolveDynamicServiceAndMethod(const Http::HeaderEntry* path) { return {}; } - const Stats::StatName service = makeDynamicStatName(request_names->service_); - const Stats::StatName method = makeDynamicStatName(request_names->method_); + Stats::Element service = Stats::DynamicName(request_names->service_); + Stats::Element method = Stats::DynamicName(request_names->method_); return RequestStatNames{service, method}; } diff --git a/source/common/grpc/context_impl.h b/source/common/grpc/context_impl.h index 9d3ddc731458b..98a34695235bb 100644 --- a/source/common/grpc/context_impl.h +++ b/source/common/grpc/context_impl.h @@ -9,6 +9,7 @@ #include "common/common/hash.h" #include "common/grpc/stat_names.h" #include "common/stats/symbol_table_impl.h" +#include "common/stats/utility.h" #include "absl/types/optional.h" @@ -16,8 +17,8 @@ namespace Envoy { namespace Grpc { struct Context::RequestStatNames { - Stats::StatName service_; // supplies the service name. - Stats::StatName method_; // supplies the method name. + Stats::Element service_; // supplies the service name. + Stats::Element method_; // supplies the method name. }; class ContextImpl : public Context { @@ -59,25 +60,13 @@ class ContextImpl : public Context { StatNames& statNames() override { return stat_names_; } private: - // Makes a stat name from a string, if we don't already have one for it. - // This always takes a lock on mutex_, and if we haven't seen the name - // before, it also takes a lock on the symbol table. - // - // TODO(jmarantz): See https://github.com/envoyproxy/envoy/pull/7008 for - // a lock-free approach to creating dynamic stat-names based on requests. - Stats::StatName makeDynamicStatName(absl::string_view name); - - // Gets the stat prefix and underlying storage, depending on whether request_names is empty - // or not. - // Prefix will be "" if request_names is empty, or - // ".." if it is not empty. - std::pair - getPrefix(Protocol protocol, const absl::optional& request_names); + // Creates an array of stat-name elements, comprising the protocol, optional + // service and method, and a suffix. + Stats::ElementVec statElements(Protocol protocol, + const absl::optional& request_names, + Stats::Element suffix); - Stats::SymbolTable& symbol_table_; - mutable Thread::MutexBasicLockable mutex_; - Stats::StatNamePool stat_name_pool_ ABSL_GUARDED_BY(mutex_); - StringMap stat_name_map_ ABSL_GUARDED_BY(mutex_); + Stats::StatNamePool stat_name_pool_; const Stats::StatName grpc_; const Stats::StatName grpc_web_; const Stats::StatName success_; diff --git a/source/common/http/BUILD b/source/common/http/BUILD index 4a8e95c24ba28..6597946f813fa 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -316,6 +316,7 @@ envoy_cc_library( "//include/envoy/stats:stats_macros", "//include/envoy/stats:timespan_interface", "//source/common/stats:symbol_table_lib", + "//source/common/stats:utility_lib", ], ) diff --git a/source/common/http/user_agent.cc b/source/common/http/user_agent.cc index ca2774376751f..d6804f245ec52 100644 --- a/source/common/http/user_agent.cc +++ b/source/common/http/user_agent.cc @@ -10,6 +10,7 @@ #include "common/http/headers.h" #include "common/stats/symbol_table_impl.h" +#include "common/stats/utility.h" namespace Envoy { namespace Http { @@ -30,17 +31,14 @@ void UserAgent::completeConnectionLength(Stats::Timespan& span) { UserAgentStats::UserAgentStats(Stats::StatName prefix, Stats::StatName device, Stats::Scope& scope, const UserAgentContext& context) - : downstream_cx_total_(scope.counterFromStatName(Stats::StatName( - context.symbol_table_.join({prefix, device, context.downstream_cx_total_}).get()))), - downstream_cx_destroy_remote_active_rq_(scope.counterFromStatName(Stats::StatName( - context.symbol_table_ - .join({prefix, device, context.downstream_cx_destroy_remote_active_rq_}) - .get()))), - downstream_rq_total_(scope.counterFromStatName(Stats::StatName( - context.symbol_table_.join({prefix, device, context.downstream_rq_total_}).get()))), - downstream_cx_length_ms_(scope.histogramFromStatName( - Stats::StatName( - context.symbol_table_.join({prefix, device, context.downstream_cx_length_ms_}).get()), + : downstream_cx_total_(Stats::Utility::counterFromElements( + scope, {prefix, device, context.downstream_cx_total_})), + downstream_cx_destroy_remote_active_rq_(Stats::Utility::counterFromElements( + scope, {prefix, device, context.downstream_cx_destroy_remote_active_rq_})), + downstream_rq_total_(Stats::Utility::counterFromElements( + scope, {prefix, device, context.downstream_rq_total_})), + downstream_cx_length_ms_(Stats::Utility::histogramFromElements( + scope, {prefix, device, context.downstream_cx_length_ms_}, Stats::Histogram::Unit::Milliseconds)) { downstream_cx_total_.inc(); downstream_rq_total_.inc(); diff --git a/source/common/stats/utility.cc b/source/common/stats/utility.cc index 18441355fd3d7..ee3944172c0d9 100644 --- a/source/common/stats/utility.cc +++ b/source/common/stats/utility.cc @@ -4,6 +4,7 @@ #include #include "absl/strings/match.h" +#include "absl/types/optional.h" namespace Envoy { namespace Stats { @@ -34,5 +35,87 @@ absl::optional Utility::findTag(const Metric& metric, StatName find_ta return value; } +namespace { + +// Helper class for the three Utility::*FromElements implementations to build up +// a joined StatName from a mix of StatName and string_view. +struct ElementVisitor { + ElementVisitor(SymbolTable& symbol_table, const ElementVec& elements) + : symbol_table_(symbol_table), pool_(symbol_table) { + stat_names_.resize(elements.size()); + for (const Element& element : elements) { + absl::visit(*this, element); + } + joined_ = symbol_table_.join(stat_names_); + } + + // Overloads provides for absl::visit to call. + void operator()(StatName stat_name) { stat_names_.push_back(stat_name); } + void operator()(absl::string_view name) { stat_names_.push_back(pool_.add(name)); } + + /** + * @return the StatName constructed by joining the elements. + */ + StatName statName() { return StatName(joined_.get()); } + + SymbolTable& symbol_table_; + StatNameVec stat_names_; + StatNameDynamicPool pool_; + SymbolTable::StoragePtr joined_; +}; + +} // namespace + +Counter& Utility::counterFromElements(Scope& scope, const ElementVec& elements, + StatNameTagVectorOptConstRef tags) { + ElementVisitor visitor(scope.symbolTable(), elements); + return scope.counterFromStatNameWithTags(visitor.statName(), tags); +} + +Counter& Utility::counterFromStatNames(Scope& scope, const StatNameVec& elements, + StatNameTagVectorOptConstRef tags) { + SymbolTable::StoragePtr joined = scope.symbolTable().join(elements); + return scope.counterFromStatNameWithTags(StatName(joined.get()), tags); +} + +Gauge& Utility::gaugeFromElements(Scope& scope, const ElementVec& elements, + Gauge::ImportMode import_mode, + StatNameTagVectorOptConstRef tags) { + ElementVisitor visitor(scope.symbolTable(), elements); + return scope.gaugeFromStatNameWithTags(visitor.statName(), tags, import_mode); +} + +Gauge& Utility::gaugeFromStatNames(Scope& scope, const StatNameVec& elements, + Gauge::ImportMode import_mode, + StatNameTagVectorOptConstRef tags) { + SymbolTable::StoragePtr joined = scope.symbolTable().join(elements); + return scope.gaugeFromStatNameWithTags(StatName(joined.get()), tags, import_mode); +} + +Histogram& Utility::histogramFromElements(Scope& scope, const ElementVec& elements, + Histogram::Unit unit, StatNameTagVectorOptConstRef tags) { + ElementVisitor visitor(scope.symbolTable(), elements); + return scope.histogramFromStatNameWithTags(visitor.statName(), tags, unit); +} + +Histogram& Utility::histogramFromStatNames(Scope& scope, const StatNameVec& elements, + Histogram::Unit unit, + StatNameTagVectorOptConstRef tags) { + SymbolTable::StoragePtr joined = scope.symbolTable().join(elements); + return scope.histogramFromStatNameWithTags(StatName(joined.get()), tags, unit); +} + +TextReadout& Utility::textReadoutFromElements(Scope& scope, const ElementVec& elements, + StatNameTagVectorOptConstRef tags) { + ElementVisitor visitor(scope.symbolTable(), elements); + return scope.textReadoutFromStatNameWithTags(visitor.statName(), tags); +} + +TextReadout& Utility::textReadoutFromStatNames(Scope& scope, const StatNameVec& elements, + StatNameTagVectorOptConstRef tags) { + SymbolTable::StoragePtr joined = scope.symbolTable().join(elements); + return scope.textReadoutFromStatNameWithTags(StatName(joined.get()), tags); +} + } // namespace Stats } // namespace Envoy diff --git a/source/common/stats/utility.h b/source/common/stats/utility.h index 0d0ed4b21bc0a..46b72234da3ab 100644 --- a/source/common/stats/utility.h +++ b/source/common/stats/utility.h @@ -2,16 +2,44 @@ #include +#include "envoy/stats/scope.h" #include "envoy/stats/stats.h" #include "common/stats/symbol_table_impl.h" +#include "absl/container/inlined_vector.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" namespace Envoy { namespace Stats { +/** + * Represents a dynamically created stat name token based on absl::string_view. + * This class wrapper is used in the 'Element' variant so that call-sites + * can express explicit intent to create dynamic stat names, which are more + * expensive than symbolic stat names. We use dynamic stat names only for + * building stats based on names discovered in the line of a request. + */ +class DynamicName : public absl::string_view { +public: + // This is intentionally left as an implicit conversion from string_view to + // make call-sites easier to read, e.g. + // Utility::counterFromElements(*scope, {DynamicName("a"), DynamicName("b")}); + DynamicName(absl::string_view str) : absl::string_view(str) {} +}; + +/** + * Holds either a symbolic StatName or a dynamic string, for the purpose of + * composing a vector to pass to Utility::counterFromElements, etc. This is + * a programming convenience to create joined stat names. It is easier to + * call the above helpers than to use SymbolTable::join(), because the helpers + * hide the memory management of the joined storage, and they allow easier + * co-mingling of symbolic and dynamic stat-name components. + */ +using Element = absl::variant; +using ElementVec = absl::InlinedVector; + /** * Common stats utility routines. */ @@ -34,6 +62,148 @@ class Utility { * @return The value of the tag, if found. */ static absl::optional findTag(const Metric& metric, StatName find_tag_name); + + /** + * Creates a counter from a vector of tokens which are used to create the + * name. The tokens can be specified as DynamicName or StatName. For + * tokens specified as DynamicName, a dynamic StatName will be created. See + * https://github.com/envoyproxy/envoy/blob/master/source/docs/stats.md#dynamic-stat-tokens + * for more detail on why symbolic StatNames are preferred when possible. + * + * See also counterFromStatNames, which is slightly faster but does not allow + * passing DynamicName(string)s as names. + * + * @param scope The scope in which to create the counter. + * @param elements The vector of mixed DynamicName and StatName + * @param tags optionally specified tags. + * @return A counter named using the joined elements. + */ + static Counter& counterFromElements(Scope& scope, const ElementVec& elements, + StatNameTagVectorOptConstRef tags = absl::nullopt); + + /** + * Creates a counter from a vector of tokens which are used to create the + * name. The tokens must be of type StatName. + * + * See also counterFromElements, which is slightly slower, but allows + * passing DynamicName(string)s as elements. + * + * @param scope The scope in which to create the counter. + * @param names The vector of StatNames + * @param tags optionally specified tags. + * @return A counter named using the joined elements. + */ + static Counter& counterFromStatNames(Scope& scope, const StatNameVec& names, + StatNameTagVectorOptConstRef tags = absl::nullopt); + + /** + * Creates a gauge from a vector of tokens which are used to create the + * name. The tokens can be specified as DynamicName or StatName. For + * tokens specified as DynamicName, a dynamic StatName will be created. See + * https://github.com/envoyproxy/envoy/blob/master/source/docs/stats.md#dynamic-stat-tokens + * for more detail on why symbolic StatNames are preferred when possible. + * + * See also gaugeFromStatNames, which is slightly faster but does not allow + * passing DynamicName(string)s as names. + * + * @param scope The scope in which to create the counter. + * @param elements The vector of mixed DynamicName and StatName + * @param import_mode Whether hot-restart should accumulate this value. + * @param tags optionally specified tags. + * @return A gauge named using the joined elements. + */ + static Gauge& gaugeFromElements(Scope& scope, const ElementVec& elements, + Gauge::ImportMode import_mode, + StatNameTagVectorOptConstRef tags = absl::nullopt); + + /** + * Creates a gauge from a vector of tokens which are used to create the + * name. The tokens must be of type StatName. + * + * See also gaugeFromElements, which is slightly slower, but allows + * passing DynamicName(string)s as elements. + * + * @param scope The scope in which to create the counter. + * @param names The vector of StatNames + * @param import_mode Whether hot-restart should accumulate this value. + * @param tags optionally specified tags. + * @return A gauge named using the joined elements. + */ + static Gauge& gaugeFromStatNames(Scope& scope, const StatNameVec& elements, + Gauge::ImportMode import_mode, + StatNameTagVectorOptConstRef tags = absl::nullopt); + + /** + * Creates a histogram from a vector of tokens which are used to create the + * name. The tokens can be specified as DynamicName or StatName. For + * tokens specified as DynamicName, a dynamic StatName will be created. See + * https://github.com/envoyproxy/envoy/blob/master/source/docs/stats.md#dynamic-stat-tokens + * for more detail on why symbolic StatNames are preferred when possible. + * + * See also histogramFromStatNames, which is slightly faster but does not allow + * passing DynamicName(string)s as names. + * + * @param scope The scope in which to create the counter. + * @param elements The vector of mixed DynamicName and StatName + * @param unit The unit of measurement. + * @param tags optionally specified tags. + * @return A histogram named using the joined elements. + */ + static Histogram& histogramFromElements(Scope& scope, const ElementVec& elements, + Histogram::Unit unit, + StatNameTagVectorOptConstRef tags = absl::nullopt); + + /** + * Creates a histogram from a vector of tokens which are used to create the + * name. The tokens must be of type StatName. + * + * See also histogramFromElements, which is slightly slower, but allows + * passing DynamicName(string)s as elements. + * + * @param scope The scope in which to create the counter. + * @param elements The vector of mixed DynamicName and StatName + * @param unit The unit of measurement. + * @param tags optionally specified tags. + * @return A histogram named using the joined elements. + */ + static Histogram& histogramFromStatNames(Scope& scope, const StatNameVec& elements, + Histogram::Unit unit, + StatNameTagVectorOptConstRef tags = absl::nullopt); + + /** + * Creates a TextReadout from a vector of tokens which are used to create the + * name. The tokens can be specified as DynamicName or StatName. For + * tokens specified as DynamicName, a dynamic StatName will be created. See + * https://github.com/envoyproxy/envoy/blob/master/source/docs/stats.md#dynamic-stat-tokens + * for more detail on why symbolic StatNames are preferred when possible. + * + * See also TextReadoutFromStatNames, which is slightly faster but does not allow + * passing DynamicName(string)s as names. + * + * @param scope The scope in which to create the counter. + * @param elements The vector of mixed DynamicName and StatName + * @param unit The unit of measurement. + * @param tags optionally specified tags. + * @return A TextReadout named using the joined elements. + */ + static TextReadout& textReadoutFromElements(Scope& scope, const ElementVec& elements, + StatNameTagVectorOptConstRef tags = absl::nullopt); + + /** + * Creates a TextReadout from a vector of tokens which are used to create the + * name. The tokens must be of type StatName. + * + * See also TextReadoutFromElements, which is slightly slower, but allows + * passing DynamicName(string)s as elements. + * + * @param scope The scope in which to create the counter. + * @param elements The vector of mixed DynamicName and StatName + * @param unit The unit of measurement. + * @param tags optionally specified tags. + * @return A TextReadout named using the joined elements. + */ + static TextReadout& textReadoutFromStatNames(Scope& scope, const StatNameVec& elements, + StatNameTagVectorOptConstRef tags = absl::nullopt); }; } // namespace Stats diff --git a/source/extensions/filters/http/dynamo/BUILD b/source/extensions/filters/http/dynamo/BUILD index 9eac6935f3304..79296db8818f5 100644 --- a/source/extensions/filters/http/dynamo/BUILD +++ b/source/extensions/filters/http/dynamo/BUILD @@ -61,5 +61,6 @@ envoy_cc_library( ":dynamo_request_parser_lib", "//include/envoy/stats:stats_interface", "//source/common/stats:symbol_table_lib", + "//source/common/stats:utility_lib", ], ) diff --git a/source/extensions/filters/http/dynamo/dynamo_stats.cc b/source/extensions/filters/http/dynamo/dynamo_stats.cc index 468c77f0a9592..06f3770a688e6 100644 --- a/source/extensions/filters/http/dynamo/dynamo_stats.cc +++ b/source/extensions/filters/http/dynamo/dynamo_stats.cc @@ -46,25 +46,21 @@ DynamoStats::DynamoStats(Stats::Scope& scope, const std::string& prefix) stat_name_set_->rememberBuiltins({"operation", "table"}); } -Stats::SymbolTable::StoragePtr DynamoStats::addPrefix(const Stats::StatNameVec& names) { - Stats::StatNameVec names_with_prefix; +Stats::ElementVec DynamoStats::addPrefix(const Stats::ElementVec& names) { + Stats::ElementVec names_with_prefix; names_with_prefix.reserve(1 + names.size()); names_with_prefix.push_back(prefix_); names_with_prefix.insert(names_with_prefix.end(), names.begin(), names.end()); - return scope_.symbolTable().join(names_with_prefix); + return names_with_prefix; } -void DynamoStats::incCounter(const Stats::StatNameVec& names) { - const Stats::SymbolTable::StoragePtr stat_name_storage = addPrefix(names); - scope_.counterFromStatName(Stats::StatName(stat_name_storage.get())).inc(); +void DynamoStats::incCounter(const Stats::ElementVec& names) { + Stats::Utility::counterFromElements(scope_, addPrefix(names)).inc(); } -void DynamoStats::recordHistogram(const Stats::StatNameVec& names, Stats::Histogram::Unit unit, +void DynamoStats::recordHistogram(const Stats::ElementVec& names, Stats::Histogram::Unit unit, uint64_t value) { - const Stats::SymbolTable::StoragePtr stat_name_storage = addPrefix(names); - Stats::Histogram& histogram = - scope_.histogramFromStatName(Stats::StatName(stat_name_storage.get()), unit); - histogram.recordValue(value); + Stats::Utility::histogramFromElements(scope_, addPrefix(names), unit).recordValue(value); } Stats::Counter& DynamoStats::buildPartitionStatCounter(const std::string& table_name, @@ -72,12 +68,11 @@ Stats::Counter& DynamoStats::buildPartitionStatCounter(const std::string& table_ const std::string& partition_id) { // Use the last 7 characters of the partition id. absl::string_view id_last_7 = absl::string_view(partition_id).substr(partition_id.size() - 7); - Stats::StatNameDynamicPool dynamic(scope_.symbolTable()); - const Stats::StatName partition = dynamic.add(absl::StrCat("__partition_id=", id_last_7)); - const Stats::SymbolTable::StoragePtr stat_name_storage = - addPrefix({table_, dynamic.add(table_name), capacity_, - getBuiltin(operation, unknown_operation_), partition}); - return scope_.counterFromStatName(Stats::StatName(stat_name_storage.get())); + std::string partition = absl::StrCat("__partition_id=", id_last_7); + return Stats::Utility::counterFromElements( + scope_, + addPrefix({table_, Stats::DynamicName(table_name), capacity_, + getBuiltin(operation, unknown_operation_), Stats::DynamicName(partition)})); } size_t DynamoStats::groupIndex(uint64_t status) { diff --git a/source/extensions/filters/http/dynamo/dynamo_stats.h b/source/extensions/filters/http/dynamo/dynamo_stats.h index 4241ec5dd711b..48399e4f4d23b 100644 --- a/source/extensions/filters/http/dynamo/dynamo_stats.h +++ b/source/extensions/filters/http/dynamo/dynamo_stats.h @@ -6,6 +6,7 @@ #include "envoy/stats/scope.h" #include "common/stats/symbol_table_impl.h" +#include "common/stats/utility.h" namespace Envoy { namespace Extensions { @@ -16,9 +17,8 @@ class DynamoStats { public: DynamoStats(Stats::Scope& scope, const std::string& prefix); - void incCounter(const Stats::StatNameVec& names); - void recordHistogram(const Stats::StatNameVec& names, Stats::Histogram::Unit unit, - uint64_t value); + void incCounter(const Stats::ElementVec& names); + void recordHistogram(const Stats::ElementVec& names, Stats::Histogram::Unit unit, uint64_t value); /** * Creates the partition id stats string. The stats format is @@ -42,7 +42,7 @@ class DynamoStats { Stats::SymbolTable& symbolTable() { return scope_.symbolTable(); } private: - Stats::SymbolTable::StoragePtr addPrefix(const Stats::StatNameVec& names); + Stats::ElementVec addPrefix(const Stats::ElementVec& names); Stats::Scope& scope_; Stats::StatNameSetPtr stat_name_set_; diff --git a/source/extensions/filters/http/fault/BUILD b/source/extensions/filters/http/fault/BUILD index 3c6e1775235db..749e04b67a4c8 100644 --- a/source/extensions/filters/http/fault/BUILD +++ b/source/extensions/filters/http/fault/BUILD @@ -33,6 +33,7 @@ envoy_cc_library( "//source/common/http:header_utility_lib", "//source/common/http:headers_lib", "//source/common/protobuf:utility_lib", + "//source/common/stats:utility_lib", "//source/extensions/filters/common/fault:fault_config_lib", "//source/extensions/filters/http:well_known_names", "@envoy_api//envoy/extensions/filters/http/fault/v3:pkg_cc_proto", diff --git a/source/extensions/filters/http/fault/fault_filter.cc b/source/extensions/filters/http/fault/fault_filter.cc index f3e277edfe6b7..a34e833bb12c6 100644 --- a/source/extensions/filters/http/fault/fault_filter.cc +++ b/source/extensions/filters/http/fault/fault_filter.cc @@ -19,6 +19,7 @@ #include "common/http/headers.h" #include "common/http/utility.h" #include "common/protobuf/utility.h" +#include "common/stats/utility.h" #include "extensions/filters/http/well_known_names.h" @@ -85,9 +86,8 @@ FaultFilterConfig::FaultFilterConfig( stats_prefix_(stat_name_set_->add(absl::StrCat(stats_prefix, "fault"))) {} void FaultFilterConfig::incCounter(Stats::StatName downstream_cluster, Stats::StatName stat_name) { - Stats::SymbolTable::StoragePtr storage = - scope_.symbolTable().join({stats_prefix_, downstream_cluster, stat_name}); - scope_.counterFromStatName(Stats::StatName(storage.get())).inc(); + Stats::Utility::counterFromStatNames(scope_, {stats_prefix_, downstream_cluster, stat_name}) + .inc(); } FaultFilter::FaultFilter(FaultFilterConfigSharedPtr config) : config_(config) {} diff --git a/source/extensions/filters/network/common/redis/BUILD b/source/extensions/filters/network/common/redis/BUILD index a7adc168788fa..d648832e0b1ee 100644 --- a/source/extensions/filters/network/common/redis/BUILD +++ b/source/extensions/filters/network/common/redis/BUILD @@ -97,5 +97,6 @@ envoy_cc_library( "//source/common/common:utility_lib", "//source/common/stats:symbol_table_lib", "//source/common/stats:timespan_lib", + "//source/common/stats:utility_lib", ], ) diff --git a/source/extensions/filters/network/common/redis/redis_command_stats.cc b/source/extensions/filters/network/common/redis/redis_command_stats.cc index 02307dc9c1c24..5a6509cf3ae6c 100644 --- a/source/extensions/filters/network/common/redis/redis_command_stats.cc +++ b/source/extensions/filters/network/common/redis/redis_command_stats.cc @@ -1,6 +1,7 @@ #include "extensions/filters/network/common/redis/redis_command_stats.h" #include "common/stats/timespan_impl.h" +#include "common/stats/utility.h" #include "extensions/filters/network/common/redis/supported_commands.h" @@ -32,33 +33,20 @@ RedisCommandStats::RedisCommandStats(Stats::SymbolTable& symbol_table, const std Extensions::NetworkFilters::Common::Redis::SupportedCommands::mset()); } -Stats::Counter& RedisCommandStats::counter(Stats::Scope& scope, - const Stats::StatNameVec& stat_names) { - const Stats::SymbolTable::StoragePtr storage_ptr = symbol_table_.join(stat_names); - Stats::StatName full_stat_name = Stats::StatName(storage_ptr.get()); - return scope.counterFromStatName(full_stat_name); -} - -Stats::Histogram& RedisCommandStats::histogram(Stats::Scope& scope, - const Stats::StatNameVec& stat_names, - Stats::Histogram::Unit unit) { - const Stats::SymbolTable::StoragePtr storage_ptr = symbol_table_.join(stat_names); - Stats::StatName full_stat_name = Stats::StatName(storage_ptr.get()); - return scope.histogramFromStatName(full_stat_name, unit); -} - Stats::TimespanPtr RedisCommandStats::createCommandTimer(Stats::Scope& scope, Stats::StatName command, Envoy::TimeSource& time_source) { return std::make_unique( - histogram(scope, {prefix_, command, latency_}, Stats::Histogram::Unit::Microseconds), + Stats::Utility::histogramFromStatNames(scope, {prefix_, command, latency_}, + Stats::Histogram::Unit::Microseconds), time_source); } Stats::TimespanPtr RedisCommandStats::createAggregateTimer(Stats::Scope& scope, Envoy::TimeSource& time_source) { return std::make_unique( - histogram(scope, {prefix_, upstream_rq_time_}, Stats::Histogram::Unit::Microseconds), + Stats::Utility::histogramFromStatNames(scope, {prefix_, upstream_rq_time_}, + Stats::Histogram::Unit::Microseconds), time_source); } @@ -84,16 +72,13 @@ Stats::StatName RedisCommandStats::getCommandFromRequest(const RespValue& reques } void RedisCommandStats::updateStatsTotal(Stats::Scope& scope, Stats::StatName command) { - counter(scope, {prefix_, command, total_}).inc(); + Stats::Utility::counterFromStatNames(scope, {prefix_, command, total_}).inc(); } void RedisCommandStats::updateStats(Stats::Scope& scope, Stats::StatName command, const bool success) { - if (success) { - counter(scope, {prefix_, command, success_}).inc(); - } else { - counter(scope, {prefix_, command, failure_}).inc(); - } + Stats::StatName status = success ? success_ : failure_; + Stats::Utility::counterFromStatNames(scope, {prefix_, command, status}).inc(); } } // namespace Redis diff --git a/source/extensions/filters/network/common/redis/redis_command_stats.h b/source/extensions/filters/network/common/redis/redis_command_stats.h index a2870ea4003e3..5dddb9f8303c9 100644 --- a/source/extensions/filters/network/common/redis/redis_command_stats.h +++ b/source/extensions/filters/network/common/redis/redis_command_stats.h @@ -28,9 +28,6 @@ class RedisCommandStats { return std::make_shared(symbol_table, "upstream_commands"); } - Stats::Counter& counter(Stats::Scope& scope, const Stats::StatNameVec& stat_names); - Stats::Histogram& histogram(Stats::Scope& scope, const Stats::StatNameVec& stat_names, - Stats::Histogram::Unit unit); Stats::TimespanPtr createCommandTimer(Stats::Scope& scope, Stats::StatName command, Envoy::TimeSource& time_source); Stats::TimespanPtr createAggregateTimer(Stats::Scope& scope, Envoy::TimeSource& time_source); diff --git a/source/extensions/filters/network/mongo_proxy/BUILD b/source/extensions/filters/network/mongo_proxy/BUILD index c4c08d4a6bc29..e471803285adb 100644 --- a/source/extensions/filters/network/mongo_proxy/BUILD +++ b/source/extensions/filters/network/mongo_proxy/BUILD @@ -89,6 +89,7 @@ envoy_cc_library( deps = [ "//include/envoy/stats:stats_interface", "//source/common/stats:symbol_table_lib", + "//source/common/stats:utility_lib", ], ) diff --git a/source/extensions/filters/network/mongo_proxy/mongo_stats.cc b/source/extensions/filters/network/mongo_proxy/mongo_stats.cc index bf9e90ce105c9..6059b461f94c4 100644 --- a/source/extensions/filters/network/mongo_proxy/mongo_stats.cc +++ b/source/extensions/filters/network/mongo_proxy/mongo_stats.cc @@ -31,23 +31,21 @@ MongoStats::MongoStats(Stats::Scope& scope, absl::string_view prefix) stat_name_set_->rememberBuiltins({"insert", "query", "update", "delete"}); } -Stats::SymbolTable::StoragePtr MongoStats::addPrefix(const std::vector& names) { - std::vector names_with_prefix; +Stats::ElementVec MongoStats::addPrefix(const Stats::ElementVec& names) { + Stats::ElementVec names_with_prefix; names_with_prefix.reserve(1 + names.size()); names_with_prefix.push_back(prefix_); names_with_prefix.insert(names_with_prefix.end(), names.begin(), names.end()); - return scope_.symbolTable().join(names_with_prefix); + return names_with_prefix; } -void MongoStats::incCounter(const std::vector& names) { - const Stats::SymbolTable::StoragePtr stat_name_storage = addPrefix(names); - scope_.counterFromStatName(Stats::StatName(stat_name_storage.get())).inc(); +void MongoStats::incCounter(const Stats::ElementVec& names) { + Stats::Utility::counterFromElements(scope_, addPrefix(names)).inc(); } -void MongoStats::recordHistogram(const std::vector& names, - Stats::Histogram::Unit unit, uint64_t sample) { - const Stats::SymbolTable::StoragePtr stat_name_storage = addPrefix(names); - scope_.histogramFromStatName(Stats::StatName(stat_name_storage.get()), unit).recordValue(sample); +void MongoStats::recordHistogram(const Stats::ElementVec& names, Stats::Histogram::Unit unit, + uint64_t sample) { + Stats::Utility::histogramFromElements(scope_, addPrefix(names), unit).recordValue(sample); } } // namespace MongoProxy diff --git a/source/extensions/filters/network/mongo_proxy/mongo_stats.h b/source/extensions/filters/network/mongo_proxy/mongo_stats.h index f49d4d34e7bfa..3571c19bbca2a 100644 --- a/source/extensions/filters/network/mongo_proxy/mongo_stats.h +++ b/source/extensions/filters/network/mongo_proxy/mongo_stats.h @@ -7,6 +7,7 @@ #include "envoy/stats/scope.h" #include "common/stats/symbol_table_impl.h" +#include "common/stats/utility.h" namespace Envoy { namespace Extensions { @@ -17,8 +18,8 @@ class MongoStats { public: MongoStats(Stats::Scope& scope, absl::string_view prefix); - void incCounter(const std::vector& names); - void recordHistogram(const std::vector& names, Stats::Histogram::Unit unit, + void incCounter(const Stats::ElementVec& names); + void recordHistogram(const Stats::ElementVec& names, Stats::Histogram::Unit unit, uint64_t sample); /** @@ -34,7 +35,7 @@ class MongoStats { Stats::SymbolTable& symbolTable() { return scope_.symbolTable(); } private: - Stats::SymbolTable::StoragePtr addPrefix(const std::vector& names); + Stats::ElementVec addPrefix(const Stats::ElementVec& names); Stats::Scope& scope_; Stats::StatNameSetPtr stat_name_set_; diff --git a/source/extensions/filters/network/mongo_proxy/proxy.cc b/source/extensions/filters/network/mongo_proxy/proxy.cc index fcbd3f6c52bb0..c764c618df1b3 100644 --- a/source/extensions/filters/network/mongo_proxy/proxy.cc +++ b/source/extensions/filters/network/mongo_proxy/proxy.cc @@ -152,17 +152,16 @@ void ProxyFilter::decodeQuery(QueryMessagePtr&& message) { } else { // Normal query, get stats on a per collection basis first. QueryMessageInfo::QueryType query_type = active_query->query_info_.type(); - Stats::StatNameVec names; + Stats::ElementVec names; names.reserve(6); // 2 entries are added by chargeQueryStats(). names.push_back(mongo_stats_->collection_); - Stats::StatNameDynamicPool dynamic(mongo_stats_->symbolTable()); - names.push_back(dynamic.add(active_query->query_info_.collection())); + names.push_back(Stats::DynamicName(active_query->query_info_.collection())); chargeQueryStats(names, query_type); // Callsite stats if we have it. if (!active_query->query_info_.callsite().empty()) { names.push_back(mongo_stats_->callsite_); - names.push_back(dynamic.add(active_query->query_info_.callsite())); + names.push_back(Stats::DynamicName(active_query->query_info_.callsite())); chargeQueryStats(names, query_type); } @@ -180,7 +179,7 @@ void ProxyFilter::decodeQuery(QueryMessagePtr&& message) { active_query_list_.emplace_back(std::move(active_query)); } -void ProxyFilter::chargeQueryStats(Stats::StatNameVec& names, +void ProxyFilter::chargeQueryStats(Stats::ElementVec& names, QueryMessageInfo::QueryType query_type) { // names come in containing {"collection", collection}. Report stats for 1 or // 2 variations on this array, and then return with the array in the same @@ -224,16 +223,15 @@ void ProxyFilter::decodeReply(ReplyMessagePtr&& message) { } if (!active_query.query_info_.command().empty()) { - Stats::StatNameVec names{mongo_stats_->cmd_, - mongo_stats_->getBuiltin(active_query.query_info_.command(), - mongo_stats_->unknown_command_)}; + Stats::ElementVec names{mongo_stats_->cmd_, + mongo_stats_->getBuiltin(active_query.query_info_.command(), + mongo_stats_->unknown_command_)}; chargeReplyStats(active_query, names, *message); } else { // Collection stats first. - Stats::StatNameDynamicPool dynamic(mongo_stats_->symbolTable()); - Stats::StatNameVec names{mongo_stats_->collection_, - dynamic.add(active_query.query_info_.collection()), - mongo_stats_->query_}; + Stats::ElementVec names{mongo_stats_->collection_, + Stats::DynamicName(active_query.query_info_.collection()), + mongo_stats_->query_}; chargeReplyStats(active_query, names, *message); // Callsite stats if we have it. @@ -242,7 +240,7 @@ void ProxyFilter::decodeReply(ReplyMessagePtr&& message) { // to mutate the array to {"collection", collection, "callsite", callsite, "query"}. ASSERT(names.size() == 3); names.back() = mongo_stats_->callsite_; // Replaces "query". - names.push_back(dynamic.add(active_query.query_info_.callsite())); + names.push_back(Stats::DynamicName(active_query.query_info_.callsite())); names.push_back(mongo_stats_->query_); chargeReplyStats(active_query, names, *message); } @@ -292,7 +290,7 @@ void ProxyFilter::onDrainClose() { read_callbacks_->connection().close(Network::ConnectionCloseType::FlushWrite); } -void ProxyFilter::chargeReplyStats(ActiveQuery& active_query, Stats::StatNameVec& names, +void ProxyFilter::chargeReplyStats(ActiveQuery& active_query, Stats::ElementVec& names, const ReplyMessage& message) { uint64_t reply_documents_byte_size = 0; for (const Bson::DocumentSharedPtr& document : message.documents()) { diff --git a/source/extensions/filters/network/mongo_proxy/proxy.h b/source/extensions/filters/network/mongo_proxy/proxy.h index 0da6146f418e8..c54308f1ae386 100644 --- a/source/extensions/filters/network/mongo_proxy/proxy.h +++ b/source/extensions/filters/network/mongo_proxy/proxy.h @@ -167,12 +167,12 @@ class ProxyFilter : public Network::Filter, // Increment counters related to queries. 'names' is passed by non-const // reference so the implementation can mutate it without copying, though it // always restores it to its prior state prior to return. - void chargeQueryStats(Stats::StatNameVec& names, QueryMessageInfo::QueryType query_type); + void chargeQueryStats(Stats::ElementVec& names, QueryMessageInfo::QueryType query_type); // Add samples to histograms related to replies. 'names' is passed by // non-const reference so the implementation can mutate it without copying, // though it always restores it to its prior state prior to return. - void chargeReplyStats(ActiveQuery& active_query, Stats::StatNameVec& names, + void chargeReplyStats(ActiveQuery& active_query, Stats::ElementVec& names, const ReplyMessage& message); void doDecode(Buffer::Instance& buffer); diff --git a/source/extensions/filters/network/zookeeper_proxy/filter.cc b/source/extensions/filters/network/zookeeper_proxy/filter.cc index 331d8a476e692..b6c38c0ec2971 100644 --- a/source/extensions/filters/network/zookeeper_proxy/filter.cc +++ b/source/extensions/filters/network/zookeeper_proxy/filter.cc @@ -154,11 +154,11 @@ void ZooKeeperFilter::onPing() { } void ZooKeeperFilter::onAuthRequest(const std::string& scheme) { - Stats::SymbolTable::StoragePtr storage = config_->scope_.symbolTable().join( - {config_->stat_prefix_, config_->auth_, - config_->stat_name_set_->getBuiltin(absl::StrCat(scheme, "_rq"), - config_->unknown_scheme_rq_)}); - config_->scope_.counterFromStatName(Stats::StatName(storage.get())).inc(); + Stats::Counter& counter = Stats::Utility::counterFromStatNames( + config_->scope_, {config_->stat_prefix_, config_->auth_, + config_->stat_name_set_->getBuiltin(absl::StrCat(scheme, "_rq"), + config_->unknown_scheme_rq_)}); + counter.inc(); setDynamicMetadata("opname", "auth"); } @@ -290,11 +290,10 @@ void ZooKeeperFilter::onConnectResponse(const int32_t proto_version, const int32 const std::chrono::milliseconds& latency) { config_->stats_.connect_resp_.inc(); - Stats::SymbolTable::StoragePtr storage = - config_->scope_.symbolTable().join({config_->stat_prefix_, config_->connect_latency_}); - config_->scope_ - .histogramFromStatName(Stats::StatName(storage.get()), Stats::Histogram::Unit::Milliseconds) - .recordValue(latency.count()); + Stats::Histogram& histogram = Stats::Utility::histogramFromElements( + config_->scope_, {config_->stat_prefix_, config_->connect_latency_}, + Stats::Histogram::Unit::Milliseconds); + histogram.recordValue(latency.count()); setDynamicMetadata({{"opname", "connect_response"}, {"protocol_version", std::to_string(proto_version)}, @@ -313,11 +312,11 @@ void ZooKeeperFilter::onResponse(const OpCodes opcode, const int32_t xid, const opname = opcode_info.opname_; opcode_latency = opcode_info.latency_name_; } - Stats::SymbolTable::StoragePtr storage = - config_->scope_.symbolTable().join({config_->stat_prefix_, opcode_latency}); - config_->scope_ - .histogramFromStatName(Stats::StatName(storage.get()), Stats::Histogram::Unit::Milliseconds) - .recordValue(latency.count()); + + Stats::Histogram& histogram = Stats::Utility::histogramFromStatNames( + config_->scope_, {config_->stat_prefix_, opcode_latency}, + Stats::Histogram::Unit::Milliseconds); + histogram.recordValue(latency.count()); setDynamicMetadata({{"opname", opname}, {"xid", std::to_string(xid)}, diff --git a/source/extensions/transport_sockets/tls/BUILD b/source/extensions/transport_sockets/tls/BUILD index 748c7b99559fb..7cf2407b61fbd 100644 --- a/source/extensions/transport_sockets/tls/BUILD +++ b/source/extensions/transport_sockets/tls/BUILD @@ -110,6 +110,7 @@ envoy_cc_library( "//source/common/network:address_lib", "//source/common/protobuf:utility_lib", "//source/common/stats:symbol_table_lib", + "//source/common/stats:utility_lib", "//source/extensions/transport_sockets/tls/private_key:private_key_manager_lib", "@envoy_api//envoy/admin/v3:pkg_cc_proto", "@envoy_api//envoy/type/matcher/v3:pkg_cc_proto", diff --git a/source/extensions/transport_sockets/tls/context_impl.cc b/source/extensions/transport_sockets/tls/context_impl.cc index 7292bba9b005f..2aaec7f14b887 100644 --- a/source/extensions/transport_sockets/tls/context_impl.cc +++ b/source/extensions/transport_sockets/tls/context_impl.cc @@ -19,6 +19,7 @@ #include "common/common/utility.h" #include "common/network/address_impl.h" #include "common/protobuf/utility.h" +#include "common/stats/utility.h" #include "extensions/transport_sockets/tls/utility.h" @@ -594,10 +595,9 @@ Envoy::Ssl::ClientValidationStatus ContextImpl::verifyCertificate( void ContextImpl::incCounter(const Stats::StatName name, absl::string_view value, const Stats::StatName fallback) const { - Stats::SymbolTable& symbol_table = scope_.symbolTable(); - Stats::SymbolTable::StoragePtr storage = - symbol_table.join({name, stat_name_set_->getBuiltin(value, fallback)}); - scope_.counterFromStatName(Stats::StatName(storage.get())).inc(); + Stats::Counter& counter = Stats::Utility::counterFromElements( + scope_, {name, stat_name_set_->getBuiltin(value, fallback)}); + counter.inc(); #ifdef LOG_BUILTIN_STAT_NAMES std::cerr << absl::StrCat("Builtin ", symbol_table.toString(name), ": ", value, "\n") diff --git a/test/common/grpc/context_impl_test.cc b/test/common/grpc/context_impl_test.cc index c1fa773b25d3c..d412dd87920f6 100644 --- a/test/common/grpc/context_impl_test.cc +++ b/test/common/grpc/context_impl_test.cc @@ -73,8 +73,8 @@ TEST(GrpcContextTest, ResolveServiceAndMethod) { absl::optional request_names = context.resolveDynamicServiceAndMethod(path); EXPECT_TRUE(request_names); - EXPECT_EQ("service_name", symbol_table->toString(request_names->service_)); - EXPECT_EQ("method_name", symbol_table->toString(request_names->method_)); + EXPECT_EQ("service_name", absl::get(request_names->service_)); + EXPECT_EQ("method_name", absl::get(request_names->method_)); headers.setPath(""); EXPECT_FALSE(context.resolveDynamicServiceAndMethod(path)); headers.setPath("/"); diff --git a/test/common/stats/BUILD b/test/common/stats/BUILD index ad8e7885cd1cb..5e38a62688363 100644 --- a/test/common/stats/BUILD +++ b/test/common/stats/BUILD @@ -241,3 +241,12 @@ envoy_cc_test_binary( "@envoy_api//envoy/config/metrics/v3:pkg_cc_proto", ], ) + +envoy_cc_test( + name = "utility_test", + srcs = ["utility_test.cc"], + deps = [ + "//source/common/stats:isolated_store_lib", + "//source/common/stats:utility_lib", + ], +) diff --git a/test/common/stats/utility_test.cc b/test/common/stats/utility_test.cc new file mode 100644 index 0000000000000..8f4ec260d3bba --- /dev/null +++ b/test/common/stats/utility_test.cc @@ -0,0 +1,112 @@ +#include + +#include "envoy/stats/stats_macros.h" + +#include "common/stats/isolated_store_impl.h" +#include "common/stats/null_counter.h" +#include "common/stats/null_gauge.h" +#include "common/stats/symbol_table_creator.h" + +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Stats { +namespace { + +class StatsUtilityTest : public testing::Test { +protected: + StatsUtilityTest() + : symbol_table_(SymbolTableCreator::makeSymbolTable()), + store_(std::make_unique(*symbol_table_)), pool_(*symbol_table_), + tags_( + {{pool_.add("tag1"), pool_.add("value1")}, {pool_.add("tag2"), pool_.add("value2")}}) {} + + ~StatsUtilityTest() override { + pool_.clear(); + store_.reset(); + EXPECT_EQ(0, symbol_table_->numSymbols()); + } + + SymbolTablePtr symbol_table_; + std::unique_ptr store_; + StatNamePool pool_; + StatNameTagVector tags_; +}; + +TEST_F(StatsUtilityTest, Counters) { + ScopePtr scope = store_->createScope("scope."); + Counter& c1 = Utility::counterFromElements(*scope, {DynamicName("a"), DynamicName("b")}); + EXPECT_EQ("scope.a.b", c1.name()); + StatName token = pool_.add("token"); + Counter& c2 = Utility::counterFromElements(*scope, {DynamicName("a"), token, DynamicName("b")}); + EXPECT_EQ("scope.a.token.b", c2.name()); + StatName suffix = pool_.add("suffix"); + Counter& c3 = Utility::counterFromElements(*scope, {token, suffix}); + EXPECT_EQ("scope.token.suffix", c3.name()); + Counter& c4 = Utility::counterFromStatNames(*scope, {token, suffix}); + EXPECT_EQ("scope.token.suffix", c4.name()); + EXPECT_EQ(&c3, &c4); + + Counter& ctags = + Utility::counterFromElements(*scope, {DynamicName("x"), token, DynamicName("y")}, tags_); + EXPECT_EQ("scope.x.token.y.tag1.value1.tag2.value2", ctags.name()); +} + +TEST_F(StatsUtilityTest, Gauges) { + ScopePtr scope = store_->createScope("scope."); + Gauge& g1 = Utility::gaugeFromElements(*scope, {DynamicName("a"), DynamicName("b")}, + Gauge::ImportMode::NeverImport); + EXPECT_EQ("scope.a.b", g1.name()); + EXPECT_EQ(Gauge::ImportMode::NeverImport, g1.importMode()); + StatName token = pool_.add("token"); + Gauge& g2 = Utility::gaugeFromElements(*scope, {DynamicName("a"), token, DynamicName("b")}, + Gauge::ImportMode::Accumulate); + EXPECT_EQ("scope.a.token.b", g2.name()); + EXPECT_EQ(Gauge::ImportMode::Accumulate, g2.importMode()); + StatName suffix = pool_.add("suffix"); + Gauge& g3 = Utility::gaugeFromElements(*scope, {token, suffix}, Gauge::ImportMode::NeverImport); + EXPECT_EQ("scope.token.suffix", g3.name()); + Gauge& g4 = Utility::gaugeFromStatNames(*scope, {token, suffix}, Gauge::ImportMode::NeverImport); + EXPECT_EQ("scope.token.suffix", g4.name()); + EXPECT_EQ(&g3, &g4); +} + +TEST_F(StatsUtilityTest, Histograms) { + ScopePtr scope = store_->createScope("scope."); + Histogram& h1 = Utility::histogramFromElements(*scope, {DynamicName("a"), DynamicName("b")}, + Histogram::Unit::Milliseconds); + EXPECT_EQ("scope.a.b", h1.name()); + EXPECT_EQ(Histogram::Unit::Milliseconds, h1.unit()); + StatName token = pool_.add("token"); + Histogram& h2 = Utility::histogramFromElements( + *scope, {DynamicName("a"), token, DynamicName("b")}, Histogram::Unit::Microseconds); + EXPECT_EQ("scope.a.token.b", h2.name()); + EXPECT_EQ(Histogram::Unit::Microseconds, h2.unit()); + StatName suffix = pool_.add("suffix"); + Histogram& h3 = Utility::histogramFromElements(*scope, {token, suffix}, Histogram::Unit::Bytes); + EXPECT_EQ("scope.token.suffix", h3.name()); + EXPECT_EQ(Histogram::Unit::Bytes, h3.unit()); + Histogram& h4 = Utility::histogramFromStatNames(*scope, {token, suffix}, Histogram::Unit::Bytes); + EXPECT_EQ(&h3, &h4); +} + +TEST_F(StatsUtilityTest, TextReadouts) { + ScopePtr scope = store_->createScope("scope."); + TextReadout& t1 = Utility::textReadoutFromElements(*scope, {DynamicName("a"), DynamicName("b")}); + EXPECT_EQ("scope.a.b", t1.name()); + StatName token = pool_.add("token"); + TextReadout& t2 = + Utility::textReadoutFromElements(*scope, {DynamicName("a"), token, DynamicName("b")}); + EXPECT_EQ("scope.a.token.b", t2.name()); + StatName suffix = pool_.add("suffix"); + TextReadout& t3 = Utility::textReadoutFromElements(*scope, {token, suffix}); + EXPECT_EQ("scope.token.suffix", t3.name()); + TextReadout& t4 = Utility::textReadoutFromStatNames(*scope, {token, suffix}); + EXPECT_EQ(&t3, &t4); +} + +} // namespace +} // namespace Stats +} // namespace Envoy