diff --git a/include/envoy/http/BUILD b/include/envoy/http/BUILD index 1a4bd81ba034..bdd112be4e1e 100644 --- a/include/envoy/http/BUILD +++ b/include/envoy/http/BUILD @@ -32,6 +32,7 @@ envoy_cc_library( envoy_cc_library( name = "codes_interface", hdrs = ["codes.h"], + deps = ["//include/envoy/stats:stats_interface"], ) envoy_cc_library( @@ -44,6 +45,15 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "context_interface", + hdrs = ["context.h"], + deps = [ + ":codes_interface", + "//include/envoy/tracing:http_tracer_interface", + ], +) + envoy_cc_library( name = "filter_interface", hdrs = ["filter.h"], diff --git a/include/envoy/http/codes.h b/include/envoy/http/codes.h index c92ec6554897..8fdf547e9db8 100644 --- a/include/envoy/http/codes.h +++ b/include/envoy/http/codes.h @@ -1,5 +1,9 @@ #pragma once +#include + +#include "envoy/stats/scope.h" + namespace Envoy { namespace Http { @@ -73,5 +77,59 @@ enum class Code { // clang-format on }; +/** + * Manages updating of statistics for HTTP Status Codes. Sets up string-tokens + * for fast combining of tokens based on scope, status-code buckets (2xx, + * 4xx...), and exact status code. + */ +class CodeStats { +public: + virtual ~CodeStats() = default; + + struct ResponseStatInfo { + Stats::Scope& global_scope_; + Stats::Scope& cluster_scope_; + const std::string& prefix_; + uint64_t response_status_code_; + bool internal_request_; + const std::string& request_vhost_name_; + const std::string& request_vcluster_name_; + const std::string& from_zone_; + const std::string& to_zone_; + bool upstream_canary_; + }; + + struct ResponseTimingInfo { + Stats::Scope& global_scope_; + Stats::Scope& cluster_scope_; + const std::string& prefix_; + std::chrono::milliseconds response_time_; + bool upstream_canary_; + bool internal_request_; + const std::string& request_vhost_name_; + const std::string& request_vcluster_name_; + const std::string& from_zone_; + const std::string& to_zone_; + }; + + /** + * Charge a simple response stat to an upstream. + */ + virtual void chargeBasicResponseStat(Stats::Scope& scope, const std::string& prefix, + Code response_code) const PURE; + + /** + * Charge a response stat to both agg counters (*xx) as well as code specific counters. This + * routine also looks for the x-envoy-upstream-canary header and if it is set, also charges + * canary stats. + */ + virtual void chargeResponseStat(const ResponseStatInfo& info) const PURE; + + /** + * Charge a response timing to the various dynamic stat postfixes. + */ + virtual void chargeResponseTiming(const ResponseTimingInfo& info) const PURE; +}; + } // namespace Http } // namespace Envoy diff --git a/include/envoy/http/context.h b/include/envoy/http/context.h new file mode 100644 index 000000000000..21f2061ae387 --- /dev/null +++ b/include/envoy/http/context.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include "envoy/http/codes.h" +#include "envoy/tracing/http_tracer.h" + +namespace Envoy { +namespace Http { + +/** + * Captures http-related structures with cardinality of one per server. + */ +class Context { +public: + virtual ~Context() = default; + virtual Tracing::HttpTracer& tracer() PURE; + virtual CodeStats& codeStats() PURE; +}; + +using ContextPtr = std::unique_ptr; + +} // namespace Http +} // namespace Envoy diff --git a/include/envoy/server/BUILD b/include/envoy/server/BUILD index f030dc62d1d6..2bb6674b7fc9 100644 --- a/include/envoy/server/BUILD +++ b/include/envoy/server/BUILD @@ -24,7 +24,6 @@ envoy_cc_library( deps = [ ":config_tracker_interface", "//include/envoy/buffer:buffer_interface", - "//include/envoy/http:codes_interface", "//include/envoy/http:filter_interface", "//include/envoy/http:header_map_interface", "//include/envoy/http:query_params_interface", @@ -37,6 +36,8 @@ envoy_cc_library( hdrs = ["configuration.h"], external_deps = ["abseil_optional"], deps = [ + "//include/envoy/http:context_interface", + "//include/envoy/ratelimit:ratelimit_interface", "//include/envoy/tracing:http_tracer_interface", "//include/envoy/upstream:cluster_manager_interface", ], @@ -94,6 +95,7 @@ envoy_cc_library( "//include/envoy/api:api_interface", "//include/envoy/common:mutex_tracer", "//include/envoy/event:timer_interface", + "//include/envoy/http:context_interface", "//include/envoy/http:query_params_interface", "//include/envoy/init:init_interface", "//include/envoy/local_info:local_info_interface", @@ -141,6 +143,8 @@ envoy_cc_library( deps = [ ":admin_interface", "//include/envoy/access_log:access_log_interface", + "//include/envoy/http:codes_interface", + "//include/envoy/http:context_interface", "//include/envoy/http:filter_interface", "//include/envoy/init:init_interface", "//include/envoy/json:json_object_interface", diff --git a/include/envoy/server/filter_config.h b/include/envoy/server/filter_config.h index 416491647a17..2183b17972b0 100644 --- a/include/envoy/server/filter_config.h +++ b/include/envoy/server/filter_config.h @@ -4,6 +4,8 @@ #include "envoy/access_log/access_log.h" #include "envoy/api/v2/core/base.pb.h" +#include "envoy/http/codes.h" +#include "envoy/http/context.h" #include "envoy/http/filter.h" #include "envoy/init/init.h" #include "envoy/json/json_object.h" @@ -133,6 +135,11 @@ class FactoryContext { * @return OverloadManager& the overload manager for the server. */ virtual OverloadManager& overloadManager() PURE; + + /** + * @return Http::Context& a reference to the http context. + */ + virtual Http::Context& httpContext() PURE; }; class ListenerFactoryContext : public FactoryContext { diff --git a/include/envoy/server/instance.h b/include/envoy/server/instance.h index 3f3c82d5c818..5bda8f1a27f7 100644 --- a/include/envoy/server/instance.h +++ b/include/envoy/server/instance.h @@ -8,6 +8,7 @@ #include "envoy/api/api.h" #include "envoy/common/mutex_tracer.h" #include "envoy/event/timer.h" +#include "envoy/http/context.h" #include "envoy/init/init.h" #include "envoy/local_info/local_info.h" #include "envoy/network/listen_socket.h" @@ -182,9 +183,9 @@ class Instance { virtual Stats::Store& stats() PURE; /** - * @return the server-wide http tracer. + * @return the server-wide http context. */ - virtual Tracing::HttpTracer& httpTracer() PURE; + virtual Http::Context& httpContext() PURE; /** * @return ThreadLocal::Instance& the thread local storage engine for the server. This is used to diff --git a/source/common/http/BUILD b/source/common/http/BUILD index 38782e5a88e3..55812a0b6e31 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -17,6 +17,7 @@ envoy_cc_library( "//include/envoy/event:dispatcher_interface", "//include/envoy/http:async_client_interface", "//include/envoy/http:codec_interface", + "//include/envoy/http:context_interface", "//include/envoy/http:header_map_interface", "//include/envoy/http:message_interface", "//include/envoy/router:router_interface", @@ -92,6 +93,17 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "context_lib", + srcs = ["context_impl.cc"], + hdrs = ["context_impl.h"], + deps = [ + ":codes_lib", + "//include/envoy/http:context_interface", + "//source/common/tracing:http_tracer_lib", + ], +) + envoy_cc_library( name = "conn_pool_base_lib", srcs = ["conn_pool_base.cc"], @@ -137,6 +149,7 @@ envoy_cc_library( "//include/envoy/event:deferred_deletable", "//include/envoy/event:dispatcher_interface", "//include/envoy/http:codec_interface", + "//include/envoy/http:context_interface", "//include/envoy/http:filter_interface", "//include/envoy/http:header_map_interface", "//include/envoy/local_info:local_info_interface", @@ -150,7 +163,6 @@ envoy_cc_library( "//include/envoy/stats:stats_interface", "//include/envoy/stats:stats_macros", "//include/envoy/stats:timespan", - "//include/envoy/tracing:http_tracer_interface", "//include/envoy/upstream:upstream_interface", "//source/common/access_log:access_log_formatter_lib", "//source/common/buffer:buffer_lib", diff --git a/source/common/http/async_client_impl.cc b/source/common/http/async_client_impl.cc index 83ee09eac452..676001d5822c 100644 --- a/source/common/http/async_client_impl.cc +++ b/source/common/http/async_client_impl.cc @@ -36,10 +36,11 @@ AsyncClientImpl::AsyncClientImpl(Upstream::ClusterInfoConstSharedPtr cluster, const LocalInfo::LocalInfo& local_info, Upstream::ClusterManager& cm, Runtime::Loader& runtime, Runtime::RandomGenerator& random, - Router::ShadowWriterPtr&& shadow_writer) + Router::ShadowWriterPtr&& shadow_writer, + Http::Context& http_context) : cluster_(cluster), config_("http.async-client.", local_info, stats_store, cm, runtime, random, - std::move(shadow_writer), true, false, false, dispatcher.timeSystem()), + std::move(shadow_writer), true, false, false, dispatcher.timeSystem(), http_context), dispatcher_(dispatcher) {} AsyncClientImpl::~AsyncClientImpl() { diff --git a/source/common/http/async_client_impl.h b/source/common/http/async_client_impl.h index ca20e1d8464d..0cd1a4491534 100644 --- a/source/common/http/async_client_impl.h +++ b/source/common/http/async_client_impl.h @@ -13,6 +13,7 @@ #include "envoy/event/dispatcher.h" #include "envoy/http/async_client.h" #include "envoy/http/codec.h" +#include "envoy/http/context.h" #include "envoy/http/header_map.h" #include "envoy/http/message.h" #include "envoy/router/router.h" @@ -42,8 +43,9 @@ class AsyncClientImpl final : public AsyncClient { AsyncClientImpl(Upstream::ClusterInfoConstSharedPtr cluster, Stats::Store& stats_store, Event::Dispatcher& dispatcher, const LocalInfo::LocalInfo& local_info, Upstream::ClusterManager& cm, Runtime::Loader& runtime, - Runtime::RandomGenerator& random, Router::ShadowWriterPtr&& shadow_writer); - ~AsyncClientImpl(); + Runtime::RandomGenerator& random, Router::ShadowWriterPtr&& shadow_writer, + Http::Context& http_context); + ~AsyncClientImpl() override; // Http::AsyncClient Request* send(MessagePtr&& request, Callbacks& callbacks, diff --git a/source/common/http/codes.cc b/source/common/http/codes.cc index 0f0562afe7ac..b302b53e0ce3 100644 --- a/source/common/http/codes.cc +++ b/source/common/http/codes.cc @@ -7,124 +7,143 @@ #include "envoy/stats/scope.h" #include "common/common/enum_to_int.h" -#include "common/common/fmt.h" #include "common/common/utility.h" #include "common/http/headers.h" #include "common/http/utility.h" +#include "absl/strings/match.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" + namespace Envoy { namespace Http { -void CodeUtility::chargeBasicResponseStat(Stats::Scope& scope, const std::string& prefix, - Code response_code) { +void CodeStatsImpl::chargeBasicResponseStat(Stats::Scope& scope, const std::string& prefix, + Code response_code) const { // Build a dynamic stat for the response code and increment it. - scope.counter(fmt::format("{}upstream_rq_completed", prefix)).inc(); - scope.counter(fmt::format("{}upstream_rq_{}", prefix, groupStringForResponseCode(response_code))) + scope.counter(absl::StrCat(prefix, upstream_rq_completed_)).inc(); + scope + .counter(absl::StrCat(prefix, upstream_rq_, + CodeUtility::groupStringForResponseCode(response_code))) .inc(); - scope.counter(fmt::format("{}upstream_rq_{}", prefix, enumToInt(response_code))).inc(); + scope.counter(absl::StrCat(prefix, upstream_rq_, enumToInt(response_code))).inc(); } -void CodeUtility::chargeResponseStat(const ResponseStatInfo& info) { +void CodeStatsImpl::chargeResponseStat(const ResponseStatInfo& info) const { const uint64_t response_code = info.response_status_code_; chargeBasicResponseStat(info.cluster_scope_, info.prefix_, static_cast(response_code)); - std::string group_string = groupStringForResponseCode(static_cast(response_code)); + std::string group_string = + CodeUtility::groupStringForResponseCode(static_cast(response_code)); // If the response is from a canary, also create canary stats. if (info.upstream_canary_) { - info.cluster_scope_.counter(fmt::format("{}canary.upstream_rq_completed", info.prefix_)).inc(); - info.cluster_scope_.counter(fmt::format("{}canary.upstream_rq_{}", info.prefix_, group_string)) + info.cluster_scope_.counter(absl::StrCat(info.prefix_, canary_upstream_rq_completed_)).inc(); + info.cluster_scope_.counter(absl::StrCat(info.prefix_, canary_upstream_rq_, group_string)) .inc(); - info.cluster_scope_.counter(fmt::format("{}canary.upstream_rq_{}", info.prefix_, response_code)) + info.cluster_scope_.counter(absl::StrCat(info.prefix_, canary_upstream_rq_, response_code)) .inc(); } // Split stats into external vs. internal. if (info.internal_request_) { - info.cluster_scope_.counter(fmt::format("{}internal.upstream_rq_completed", info.prefix_)) - .inc(); - info.cluster_scope_ - .counter(fmt::format("{}internal.upstream_rq_{}", info.prefix_, group_string)) + info.cluster_scope_.counter(absl::StrCat(info.prefix_, internal_upstream_rq_completed_)).inc(); + info.cluster_scope_.counter(absl::StrCat(info.prefix_, internal_upstream_rq_, group_string)) .inc(); - info.cluster_scope_ - .counter(fmt::format("{}internal.upstream_rq_{}", info.prefix_, response_code)) + info.cluster_scope_.counter(absl::StrCat(info.prefix_, internal_upstream_rq_, response_code)) .inc(); } else { - info.cluster_scope_.counter(fmt::format("{}external.upstream_rq_completed", info.prefix_)) + info.cluster_scope_.counter(absl::StrCat(info.prefix_, external_upstream_rq_completed_)).inc(); + info.cluster_scope_.counter(absl::StrCat(info.prefix_, external_upstream_rq_, group_string)) .inc(); - info.cluster_scope_ - .counter(fmt::format("{}external.upstream_rq_{}", info.prefix_, group_string)) - .inc(); - info.cluster_scope_ - .counter(fmt::format("{}external.upstream_rq_{}", info.prefix_, response_code)) + info.cluster_scope_.counter(absl::StrCat(info.prefix_, external_upstream_rq_, response_code)) .inc(); } // Handle request virtual cluster. if (!info.request_vcluster_name_.empty()) { info.global_scope_ - .counter(fmt::format("vhost.{}.vcluster.{}.upstream_rq_completed", info.request_vhost_name_, - info.request_vcluster_name_)) + .counter(join({vhost_, info.request_vhost_name_, vcluster_, info.request_vcluster_name_, + upstream_rq_completed_})) .inc(); info.global_scope_ - .counter(fmt::format("vhost.{}.vcluster.{}.upstream_rq_{}", info.request_vhost_name_, - info.request_vcluster_name_, group_string)) + .counter(join({vhost_, info.request_vhost_name_, vcluster_, info.request_vcluster_name_, + absl::StrCat(upstream_rq_, group_string)})) .inc(); info.global_scope_ - .counter(fmt::format("vhost.{}.vcluster.{}.upstream_rq_{}", info.request_vhost_name_, - info.request_vcluster_name_, response_code)) + .counter(join({vhost_, info.request_vhost_name_, vcluster_, info.request_vcluster_name_, + absl::StrCat(upstream_rq_, response_code)})) .inc(); } // Handle per zone stats. if (!info.from_zone_.empty() && !info.to_zone_.empty()) { + absl::string_view prefix_without_trailing_dot = stripTrailingDot(info.prefix_); info.cluster_scope_ - .counter(fmt::format("{}zone.{}.{}.upstream_rq_completed", info.prefix_, info.from_zone_, - info.to_zone_)) + .counter(join({prefix_without_trailing_dot, zone_, info.from_zone_, info.to_zone_, + upstream_rq_completed_})) .inc(); info.cluster_scope_ - .counter(fmt::format("{}zone.{}.{}.upstream_rq_{}", info.prefix_, info.from_zone_, - info.to_zone_, group_string)) + .counter(join({prefix_without_trailing_dot, zone_, info.from_zone_, info.to_zone_, + absl::StrCat(upstream_rq_, group_string)})) .inc(); info.cluster_scope_ - .counter(fmt::format("{}zone.{}.{}.upstream_rq_{}", info.prefix_, info.from_zone_, - info.to_zone_, response_code)) + .counter(join({prefix_without_trailing_dot, zone_, info.from_zone_, info.to_zone_, + absl::StrCat(upstream_rq_, response_code)})) .inc(); } } -void CodeUtility::chargeResponseTiming(const ResponseTimingInfo& info) { - info.cluster_scope_.histogram(info.prefix_ + "upstream_rq_time") +void CodeStatsImpl::chargeResponseTiming(const ResponseTimingInfo& info) const { + info.cluster_scope_.histogram(absl::StrCat(info.prefix_, upstream_rq_time_)) .recordValue(info.response_time_.count()); if (info.upstream_canary_) { - info.cluster_scope_.histogram(info.prefix_ + "canary.upstream_rq_time") + info.cluster_scope_.histogram(absl::StrCat(info.prefix_, canary_upstream_rq_time_)) .recordValue(info.response_time_.count()); } if (info.internal_request_) { - info.cluster_scope_.histogram(info.prefix_ + "internal.upstream_rq_time") + info.cluster_scope_.histogram(absl::StrCat(info.prefix_, internal_upstream_rq_time_)) .recordValue(info.response_time_.count()); } else { - info.cluster_scope_.histogram(info.prefix_ + "external.upstream_rq_time") + info.cluster_scope_.histogram(absl::StrCat(info.prefix_, external_upstream_rq_time_)) .recordValue(info.response_time_.count()); } if (!info.request_vcluster_name_.empty()) { info.global_scope_ - .histogram("vhost." + info.request_vhost_name_ + ".vcluster." + - info.request_vcluster_name_ + ".upstream_rq_time") + .histogram(join({vhost_, info.request_vhost_name_, vcluster_, info.request_vcluster_name_, + upstream_rq_time_})) .recordValue(info.response_time_.count()); } // Handle per zone stats. if (!info.from_zone_.empty() && !info.to_zone_.empty()) { info.cluster_scope_ - .histogram(fmt::format("{}zone.{}.{}.upstream_rq_time", info.prefix_, info.from_zone_, - info.to_zone_)) + .histogram(join({stripTrailingDot(info.prefix_), zone_, info.from_zone_, info.to_zone_, + upstream_rq_time_})) .recordValue(info.response_time_.count()); } } +absl::string_view CodeStatsImpl::stripTrailingDot(absl::string_view str) { + if (absl::EndsWith(str, ".")) { + str.remove_suffix(1); + } + return str; +} + +std::string CodeStatsImpl::join(const std::vector& v) { + if (v.empty()) { + return ""; + } + auto iter = v.begin(); + if (iter->empty()) { + ++iter; // Skip any initial empty prefix. + } + return absl::StrJoin(iter, v.end(), "."); +} + std::string CodeUtility::groupStringForResponseCode(Code response_code) { if (CodeUtility::is2xx(enumToInt(response_code))) { return "2xx"; diff --git a/source/common/http/codes.h b/source/common/http/codes.h index c621b361d6ea..f465d9d62531 100644 --- a/source/common/http/codes.h +++ b/source/common/http/codes.h @@ -11,55 +11,67 @@ namespace Envoy { namespace Http { -/** - * General utility routines for HTTP codes. - */ -class CodeUtility { +class CodeStatsImpl : public CodeStats { public: - /** - * Charge a simple response stat to an upstream. - */ - static void chargeBasicResponseStat(Stats::Scope& scope, const std::string& prefix, - Code response_code); + ~CodeStatsImpl() override = default; - struct ResponseStatInfo { - Stats::Scope& global_scope_; - Stats::Scope& cluster_scope_; - const std::string& prefix_; - uint64_t response_status_code_; - bool internal_request_; - const std::string& request_vhost_name_; - const std::string& request_vcluster_name_; - const std::string& from_zone_; - const std::string& to_zone_; - bool upstream_canary_; - }; + // CodeStats + void chargeBasicResponseStat(Stats::Scope& scope, const std::string& prefix, + Code response_code) const override; + void chargeResponseStat(const ResponseStatInfo& info) const override; + void chargeResponseTiming(const ResponseTimingInfo& info) const override; + +private: + friend class CodeStatsTest; /** - * Charge a response stat to both agg counters (*xx) as well as code specific counters. This - * routine also looks for the x-envoy-upstream-canary header and if it is set, also charges - * canary stats. + * Strips any trailing "." from a prefix. This is handy as most prefixes + * are specified as a literal like "http.", or an empty-string "". We + * are going to be passing these, as well as other tokens, to join() below, + * which will add "." between each token. + * + * TODO(jmarantz): remove all the trailing dots in all stat prefix string + * literals. Then this function can be removed. */ - static void chargeResponseStat(const ResponseStatInfo& info); - - struct ResponseTimingInfo { - Stats::Scope& global_scope_; - Stats::Scope& cluster_scope_; - const std::string& prefix_; - std::chrono::milliseconds response_time_; - bool upstream_canary_; - bool internal_request_; - const std::string& request_vhost_name_; - const std::string& request_vcluster_name_; - const std::string& from_zone_; - const std::string& to_zone_; - }; + static absl::string_view stripTrailingDot(absl::string_view prefix); /** - * Charge a response timing to the various dynamic stat postfixes. + * Joins a string-view vector with "." between each token. If there's an + * initial blank token it is skipped. Leading blank tokens occur due to empty + * prefixes, which are fairly common. + * + * Note: this layer probably should be called something other than join(), + * like joinSkipppingLeadingEmptyToken but I thought the decrease in + * readability at all the call-sites would not be worth it. */ - static void chargeResponseTiming(const ResponseTimingInfo& info); + static std::string join(const std::vector& v); + // Predeclared tokens used for combining with join(). + const absl::string_view canary_upstream_rq_completed_{"canary.upstream_rq_completed"}; + const absl::string_view canary_upstream_rq_time_{"canary.upstream_rq_time"}; + const absl::string_view canary_upstream_rq_{"canary.upstream_rq_"}; + const absl::string_view external_rq_time_{"external.upstream_rq_time"}; + const absl::string_view external_upstream_rq_completed_{"external.upstream_rq_completed"}; + const absl::string_view external_upstream_rq_time_{"external.upstream_rq_time"}; + const absl::string_view external_upstream_rq_{"external.upstream_rq_"}; + const absl::string_view internal_rq_time_{"internal.upstream_rq_time"}; + const absl::string_view internal_upstream_rq_completed_{"internal.upstream_rq_completed"}; + const absl::string_view internal_upstream_rq_time_{"internal.upstream_rq_time"}; + const absl::string_view internal_upstream_rq_{"internal.upstream_rq_"}; + const absl::string_view upstream_rq_completed_{"upstream_rq_completed"}; + const absl::string_view upstream_rq_time_{"upstream_rq_time"}; + const absl::string_view upstream_rq_time{"upstream_rq_time"}; + const absl::string_view upstream_rq_{"upstream_rq_"}; + const absl::string_view vcluster_{"vcluster"}; + const absl::string_view vhost_{"vhost"}; + const absl::string_view zone_{"zone"}; +}; + +/** + * General utility routines for HTTP codes. + */ +class CodeUtility { +public: /** * Convert an HTTP response code to a descriptive string. * @param code supplies the code to convert. diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index f9a5654df84d..5568e44670ad 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -57,14 +57,14 @@ ConnectionManagerImpl::generateListenerStats(const std::string& prefix, Stats::S ConnectionManagerImpl::ConnectionManagerImpl(ConnectionManagerConfig& config, const Network::DrainDecision& drain_close, Runtime::RandomGenerator& random_generator, - Tracing::HttpTracer& tracer, Runtime::Loader& runtime, + Http::Context& http_context, Runtime::Loader& runtime, const LocalInfo::LocalInfo& local_info, Upstream::ClusterManager& cluster_manager, Server::OverloadManager* overload_manager, Event::TimeSystem& time_system) : config_(config), stats_(config_.stats()), conn_length_(new Stats::Timespan(stats_.named_.downstream_cx_length_ms_, time_system)), - drain_close_(drain_close), random_generator_(random_generator), tracer_(tracer), + drain_close_(drain_close), random_generator_(random_generator), http_context_(http_context), runtime_(runtime), local_info_(local_info), cluster_manager_(cluster_manager), listener_stats_(config_.listenerStats()), overload_stop_accepting_requests_ref_( @@ -692,8 +692,8 @@ void ConnectionManagerImpl::ActiveStream::traceRequest() { ConnectionManagerImpl::chargeTracingStats(tracing_decision.reason, connection_manager_.config_.tracingStats()); - active_span_ = connection_manager_.tracer_.startSpan(*this, *request_headers_, stream_info_, - tracing_decision); + active_span_ = connection_manager_.tracer().startSpan(*this, *request_headers_, stream_info_, + tracing_decision); if (!active_span_) { return; diff --git a/source/common/http/conn_manager_impl.h b/source/common/http/conn_manager_impl.h index 45bd3303ef0e..b7bd69d0c698 100644 --- a/source/common/http/conn_manager_impl.h +++ b/source/common/http/conn_manager_impl.h @@ -11,6 +11,8 @@ #include "envoy/access_log/access_log.h" #include "envoy/event/deferred_deletable.h" #include "envoy/http/codec.h" +#include "envoy/http/codes.h" +#include "envoy/http/context.h" #include "envoy/http/filter.h" #include "envoy/network/connection.h" #include "envoy/network/drain_decision.h" @@ -21,7 +23,6 @@ #include "envoy/ssl/connection.h" #include "envoy/stats/scope.h" #include "envoy/stats/stats_macros.h" -#include "envoy/tracing/http_tracer.h" #include "envoy/upstream/upstream.h" #include "common/buffer/watermark_buffer.h" @@ -47,7 +48,7 @@ class ConnectionManagerImpl : Logger::Loggable, public Network::ConnectionCallbacks { public: ConnectionManagerImpl(ConnectionManagerConfig& config, const Network::DrainDecision& drain_close, - Runtime::RandomGenerator& random_generator, Tracing::HttpTracer& tracer, + Runtime::RandomGenerator& random_generator, Http::Context& http_context, Runtime::Loader& runtime, const LocalInfo::LocalInfo& local_info, Upstream::ClusterManager& cluster_manager, Server::OverloadManager* overload_manager, Event::TimeSystem& time_system); @@ -450,6 +451,7 @@ class ConnectionManagerImpl : Logger::Loggable, void onIdleTimeout(); void onDrainTimeout(); void startDrainSequence(); + Tracing::HttpTracer& tracer() { return http_context_.tracer(); } enum class DrainState { NotDraining, Draining, Closing }; @@ -468,7 +470,7 @@ class ConnectionManagerImpl : Logger::Loggable, Event::TimerPtr connection_idle_timer_; Event::TimerPtr drain_timer_; Runtime::RandomGenerator& random_generator_; - Tracing::HttpTracer& tracer_; + Http::Context& http_context_; Runtime::Loader& runtime_; const LocalInfo::LocalInfo& local_info_; Upstream::ClusterManager& cluster_manager_; diff --git a/source/common/http/context_impl.cc b/source/common/http/context_impl.cc new file mode 100644 index 000000000000..0fc4791f0256 --- /dev/null +++ b/source/common/http/context_impl.cc @@ -0,0 +1,9 @@ +#include "common/http/context_impl.h" + +namespace Envoy { +namespace Http { + +ContextImpl::ContextImpl() : tracer_(&null_tracer_) {} + +} // namespace Http +} // namespace Envoy diff --git a/source/common/http/context_impl.h b/source/common/http/context_impl.h new file mode 100644 index 000000000000..a499af6ceda3 --- /dev/null +++ b/source/common/http/context_impl.h @@ -0,0 +1,31 @@ +#pragma once + +#include "envoy/http/context.h" + +#include "common/http/codes.h" +#include "common/tracing/http_tracer_impl.h" + +namespace Envoy { +namespace Http { + +/** + * Captures http-related structures with cardinality of one per server. + */ +class ContextImpl : public Context { +public: + ContextImpl(); + ~ContextImpl() override = default; + + Tracing::HttpTracer& tracer() override { return *tracer_; } + CodeStats& codeStats() override { return code_stats_; } + + void setTracer(Tracing::HttpTracer& tracer) { tracer_ = &tracer; } + +private: + Tracing::HttpNullTracer null_tracer_; + Tracing::HttpTracer* tracer_; + Http::CodeStatsImpl code_stats_; +}; + +} // namespace Http +} // namespace Envoy diff --git a/source/common/router/router.cc b/source/common/router/router.cc index 52986224e76b..15bb4aaf74d0 100644 --- a/source/common/router/router.cc +++ b/source/common/router/router.cc @@ -155,28 +155,29 @@ void Filter::chargeUpstreamCode(uint64_t response_status_code, const std::string zone_name = config_.local_info_.zoneName(); const std::string upstream_zone = upstreamZone(upstream_host); - Http::CodeUtility::ResponseStatInfo info{config_.scope_, - cluster_->statsScope(), - EMPTY_STRING, - response_status_code, - internal_request, - route_entry_->virtualHost().name(), - request_vcluster_ ? request_vcluster_->name() - : EMPTY_STRING, - zone_name, - upstream_zone, - is_canary}; - - Http::CodeUtility::chargeResponseStat(info); + Http::CodeStats::ResponseStatInfo info{config_.scope_, + cluster_->statsScope(), + EMPTY_STRING, + response_status_code, + internal_request, + route_entry_->virtualHost().name(), + request_vcluster_ ? request_vcluster_->name() + : EMPTY_STRING, + zone_name, + upstream_zone, + is_canary}; + + Http::CodeStats& code_stats = httpContext().codeStats(); + code_stats.chargeResponseStat(info); if (!alt_stat_prefix_.empty()) { - Http::CodeUtility::ResponseStatInfo info{config_.scope_, cluster_->statsScope(), - alt_stat_prefix_, response_status_code, - internal_request, EMPTY_STRING, - EMPTY_STRING, zone_name, - upstream_zone, is_canary}; + Http::CodeStats::ResponseStatInfo info{config_.scope_, cluster_->statsScope(), + alt_stat_prefix_, response_status_code, + internal_request, EMPTY_STRING, + EMPTY_STRING, zone_name, + upstream_zone, is_canary}; - Http::CodeUtility::chargeResponseStat(info); + code_stats.chargeResponseStat(info); } if (dropped) { @@ -624,8 +625,9 @@ void Filter::onUpstreamHeaders(const uint64_t response_code, Http::HeaderMapPtr& // upstream_request_. const auto upstream_host = upstream_request_->upstream_host_; if (retry_status == RetryStatus::Yes && setupRetry(end_stream)) { - Http::CodeUtility::chargeBasicResponseStat(cluster_->statsScope(), "retry.", - static_cast(response_code)); + Http::CodeStats& code_stats = httpContext().codeStats(); + code_stats.chargeBasicResponseStat(cluster_->statsScope(), "retry.", + static_cast(response_code)); upstream_host->stats().rq_error_.inc(); return; } else if (retry_status == RetryStatus::NoOverflow) { @@ -725,33 +727,34 @@ void Filter::onUpstreamComplete() { // TODO(mattklein123): Remove copy when G string compat issues are fixed. const std::string zone_name = config_.local_info_.zoneName(); - Http::CodeUtility::ResponseTimingInfo info{config_.scope_, + Http::CodeStats& code_stats = httpContext().codeStats(); + Http::CodeStats::ResponseTimingInfo info{config_.scope_, + cluster_->statsScope(), + EMPTY_STRING, + response_time, + upstream_request_->upstream_canary_, + internal_request, + route_entry_->virtualHost().name(), + request_vcluster_ ? request_vcluster_->name() + : EMPTY_STRING, + zone_name, + upstreamZone(upstream_request_->upstream_host_)}; + + code_stats.chargeResponseTiming(info); + + if (!alt_stat_prefix_.empty()) { + Http::CodeStats::ResponseTimingInfo info{config_.scope_, cluster_->statsScope(), - EMPTY_STRING, + alt_stat_prefix_, response_time, upstream_request_->upstream_canary_, internal_request, - route_entry_->virtualHost().name(), - request_vcluster_ ? request_vcluster_->name() - : EMPTY_STRING, + EMPTY_STRING, + EMPTY_STRING, zone_name, upstreamZone(upstream_request_->upstream_host_)}; - Http::CodeUtility::chargeResponseTiming(info); - - if (!alt_stat_prefix_.empty()) { - Http::CodeUtility::ResponseTimingInfo info{config_.scope_, - cluster_->statsScope(), - alt_stat_prefix_, - response_time, - upstream_request_->upstream_canary_, - internal_request, - EMPTY_STRING, - EMPTY_STRING, - zone_name, - upstreamZone(upstream_request_->upstream_host_)}; - - Http::CodeUtility::chargeResponseTiming(info); + code_stats.chargeResponseTiming(info); } } diff --git a/source/common/router/router.h b/source/common/router/router.h index 8d96abd11e04..e9b6d045527f 100644 --- a/source/common/router/router.h +++ b/source/common/router/router.h @@ -98,12 +98,12 @@ class FilterConfig { Stats::Scope& scope, Upstream::ClusterManager& cm, Runtime::Loader& runtime, Runtime::RandomGenerator& random, ShadowWriterPtr&& shadow_writer, bool emit_dynamic_stats, bool start_child_span, bool suppress_envoy_headers, - TimeSource& time_source) + TimeSource& time_source, Http::Context& http_context) : scope_(scope), local_info_(local_info), cm_(cm), runtime_(runtime), random_(random), stats_{ALL_ROUTER_STATS(POOL_COUNTER_PREFIX(scope, stat_prefix))}, emit_dynamic_stats_(emit_dynamic_stats), start_child_span_(start_child_span), - suppress_envoy_headers_(suppress_envoy_headers), shadow_writer_(std::move(shadow_writer)), - time_source_(time_source) {} + suppress_envoy_headers_(suppress_envoy_headers), http_context_(http_context), + shadow_writer_(std::move(shadow_writer)), time_source_(time_source) {} FilterConfig(const std::string& stat_prefix, Server::Configuration::FactoryContext& context, ShadowWriterPtr&& shadow_writer, @@ -112,7 +112,7 @@ class FilterConfig { context.runtime(), context.random(), std::move(shadow_writer), PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, dynamic_stats, true), config.start_child_span(), config.suppress_envoy_headers(), - context.timeSource()) { + context.timeSource(), context.httpContext()) { for (const auto& upstream_log : config.upstream_log()) { upstream_logs_.push_back(AccessLog::AccessLogFactory::fromProto(upstream_log, context)); } @@ -131,6 +131,7 @@ class FilterConfig { const bool start_child_span_; const bool suppress_envoy_headers_; std::list upstream_logs_; + Http::Context& http_context_; private: ShadowWriterPtr shadow_writer_; @@ -384,6 +385,7 @@ class Filter : Logger::Loggable, // and handle difference between gRPC and non-gRPC requests. void handleNon5xxResponseHeaders(const Http::HeaderMap& headers, bool end_stream); TimeSource& timeSource() { return config_.timeSource(); } + Http::Context& httpContext() { return config_.http_context_; } FilterConfig& config_; Http::StreamDecoderFilterCallbacks* callbacks_{}; diff --git a/source/common/upstream/cluster_manager_impl.cc b/source/common/upstream/cluster_manager_impl.cc index b920f376f0ce..0a6b81539d7b 100644 --- a/source/common/upstream/cluster_manager_impl.cc +++ b/source/common/upstream/cluster_manager_impl.cc @@ -167,14 +167,12 @@ void ClusterManagerInitHelper::setInitializedCb(std::function callback) } } -ClusterManagerImpl::ClusterManagerImpl(const envoy::config::bootstrap::v2::Bootstrap& bootstrap, - ClusterManagerFactory& factory, Stats::Store& stats, - ThreadLocal::Instance& tls, Runtime::Loader& runtime, - Runtime::RandomGenerator& random, - const LocalInfo::LocalInfo& local_info, - AccessLog::AccessLogManager& log_manager, - Event::Dispatcher& main_thread_dispatcher, - Server::Admin& admin, Api::Api& api) +ClusterManagerImpl::ClusterManagerImpl( + const envoy::config::bootstrap::v2::Bootstrap& bootstrap, ClusterManagerFactory& factory, + Stats::Store& stats, ThreadLocal::Instance& tls, Runtime::Loader& runtime, + Runtime::RandomGenerator& random, const LocalInfo::LocalInfo& local_info, + AccessLog::AccessLogManager& log_manager, Event::Dispatcher& main_thread_dispatcher, + Server::Admin& admin, Api::Api& api, Http::Context& http_context) : factory_(factory), runtime_(runtime), stats_(stats), tls_(tls.allocateSlot()), random_(random), log_manager_(log_manager), bind_config_(bootstrap.cluster_manager().upstream_bind_config()), local_info_(local_info), @@ -182,7 +180,8 @@ ClusterManagerImpl::ClusterManagerImpl(const envoy::config::bootstrap::v2::Boots init_helper_([this](Cluster& cluster) { onClusterInit(cluster); }), config_tracker_entry_( admin.getConfigTracker().add("clusters", [this] { return dumpClusterConfigs(); })), - time_source_(main_thread_dispatcher.timeSystem()), dispatcher_(main_thread_dispatcher) { + time_source_(main_thread_dispatcher.timeSystem()), dispatcher_(main_thread_dispatcher), + http_context_(http_context) { async_client_manager_ = std::make_unique(*this, tls, time_source_, api); const auto& cm_config = bootstrap.cluster_manager(); @@ -1021,7 +1020,8 @@ ClusterManagerImpl::ThreadLocalClusterManagerImpl::ClusterEntry::ClusterEntry( http_async_client_(cluster, parent.parent_.stats_, parent.thread_local_dispatcher_, parent.parent_.local_info_, parent.parent_, parent.parent_.runtime_, parent.parent_.random_, - Router::ShadowWriterPtr{new Router::ShadowWriterImpl(parent.parent_)}) { + Router::ShadowWriterPtr{new Router::ShadowWriterImpl(parent.parent_)}, + parent_.parent_.http_context_) { priority_set_.getOrCreateHostSet(0); // TODO(mattklein123): Consider converting other LBs over to thread local. All of them could @@ -1180,7 +1180,7 @@ ClusterManagerPtr ProdClusterManagerFactory::clusterManagerFromProto( Server::Admin& admin) { return ClusterManagerPtr{new ClusterManagerImpl(bootstrap, *this, stats, tls, runtime, random, local_info, log_manager, main_thread_dispatcher_, - admin, api_)}; + admin, api_, http_context_)}; } Http::ConnectionPool::InstancePtr ProdClusterManagerFactory::allocateConnPool( diff --git a/source/common/upstream/cluster_manager_impl.h b/source/common/upstream/cluster_manager_impl.h index adc474aa2b39..e074d24df4b8 100644 --- a/source/common/upstream/cluster_manager_impl.h +++ b/source/common/upstream/cluster_manager_impl.h @@ -40,9 +40,10 @@ class ProdClusterManagerFactory : public ClusterManagerFactory { Ssl::ContextManager& ssl_context_manager, Event::Dispatcher& main_thread_dispatcher, const LocalInfo::LocalInfo& local_info, - Secret::SecretManager& secret_manager, Api::Api& api) - : main_thread_dispatcher_(main_thread_dispatcher), api_(api), runtime_(runtime), - stats_(stats), tls_(tls), random_(random), dns_resolver_(dns_resolver), + Secret::SecretManager& secret_manager, Api::Api& api, + Http::Context& http_context) + : main_thread_dispatcher_(main_thread_dispatcher), api_(api), http_context_(http_context), + runtime_(runtime), stats_(stats), tls_(tls), random_(random), dns_resolver_(dns_resolver), ssl_context_manager_(ssl_context_manager), local_info_(local_info), secret_manager_(secret_manager) {} @@ -73,6 +74,7 @@ class ProdClusterManagerFactory : public ClusterManagerFactory { protected: Event::Dispatcher& main_thread_dispatcher_; Api::Api& api_; + Http::Context& http_context_; private: Runtime::Loader& runtime_; @@ -170,8 +172,8 @@ class ClusterManagerImpl : public ClusterManager, Logger::Loggable(proto_config, context.localInfo(), context.scope(), - context.runtime(), context.clusterManager()); + const auto filter_config = std::make_shared( + proto_config, context.localInfo(), context.scope(), context.runtime(), + context.clusterManager(), context.httpContext()); if (proto_config.has_http_service()) { const uint32_t timeout_ms = PROTOBUF_GET_MS_OR_DEFAULT(proto_config.http_service().server_uri(), diff --git a/source/extensions/filters/http/ext_authz/ext_authz.cc b/source/extensions/filters/http/ext_authz/ext_authz.cc index e7c04fb4ca17..eef14c6ccb0e 100644 --- a/source/extensions/filters/http/ext_authz/ext_authz.cc +++ b/source/extensions/filters/http/ext_authz/ext_authz.cc @@ -110,17 +110,17 @@ void Filter::onComplete(Filters::Common::ExtAuthz::ResponsePtr&& response) { case CheckStatus::Denied: cluster_->statsScope().counter("ext_authz.denied").inc(); - Http::CodeUtility::ResponseStatInfo info{config_->scope(), - cluster_->statsScope(), - EMPTY_STRING, - enumToInt(response->status_code), - true, - EMPTY_STRING, - EMPTY_STRING, - EMPTY_STRING, - EMPTY_STRING, - false}; - Http::CodeUtility::chargeResponseStat(info); + Http::CodeStats::ResponseStatInfo info{config_->scope(), + cluster_->statsScope(), + EMPTY_STRING, + enumToInt(response->status_code), + true, + EMPTY_STRING, + EMPTY_STRING, + EMPTY_STRING, + EMPTY_STRING, + false}; + config_->httpContext().codeStats().chargeResponseStat(info); break; } diff --git a/source/extensions/filters/http/ext_authz/ext_authz.h b/source/extensions/filters/http/ext_authz/ext_authz.h index 02f4cd5ea03f..b90c3274c619 100644 --- a/source/extensions/filters/http/ext_authz/ext_authz.h +++ b/source/extensions/filters/http/ext_authz/ext_authz.h @@ -37,7 +37,7 @@ class FilterConfig { public: FilterConfig(const envoy::config::filter::http::ext_authz::v2alpha::ExtAuthz& config, const LocalInfo::LocalInfo& local_info, Stats::Scope& scope, - Runtime::Loader& runtime, Upstream::ClusterManager& cm) + Runtime::Loader& runtime, Upstream::ClusterManager& cm, Http::Context& http_context) : local_info_(local_info), scope_(scope), runtime_(runtime), cm_(cm), cluster_name_(config.grpc_service().envoy_grpc().cluster_name()), allowed_authorization_headers_( @@ -45,7 +45,8 @@ class FilterConfig { allowed_request_headers_(toRequestHeaders(config.http_service().allowed_request_headers())), failure_mode_allow_(config.failure_mode_allow()), authorization_headers_to_add_( - toAuthorizationHeadersToAdd(config.http_service().authorization_headers_to_add())) {} + toAuthorizationHeadersToAdd(config.http_service().authorization_headers_to_add())), + http_context_(http_context) {} const LocalInfo::LocalInfo& localInfo() const { return local_info_; } Runtime::Loader& runtime() { return runtime_; } @@ -63,6 +64,8 @@ class FilterConfig { return authorization_headers_to_add_; } + Http::Context& httpContext() { return http_context_; } + private: static Http::LowerCaseStrUnorderedSet toRequestHeaders( const Protobuf::RepeatedPtrField& request_headers) { @@ -107,6 +110,7 @@ class FilterConfig { Http::LowerCaseStrUnorderedSet allowed_request_headers_; bool failure_mode_allow_; const Filters::Common::ExtAuthz::HeaderKeyValueVector authorization_headers_to_add_; + Http::Context& http_context_; }; typedef std::shared_ptr FilterConfigSharedPtr; diff --git a/source/extensions/filters/http/ratelimit/config.cc b/source/extensions/filters/http/ratelimit/config.cc index 262c3fff6a7c..0a66d7430d6b 100644 --- a/source/extensions/filters/http/ratelimit/config.cc +++ b/source/extensions/filters/http/ratelimit/config.cc @@ -22,8 +22,9 @@ Http::FilterFactoryCb RateLimitFilterConfig::createFilterFactoryFromProtoTyped( const envoy::config::filter::http::rate_limit::v2::RateLimit& proto_config, const std::string&, Server::Configuration::FactoryContext& context) { ASSERT(!proto_config.domain().empty()); - FilterConfigSharedPtr filter_config( - new FilterConfig(proto_config, context.localInfo(), context.scope(), context.runtime())); + FilterConfigSharedPtr filter_config(new FilterConfig(proto_config, context.localInfo(), + context.scope(), context.runtime(), + context.httpContext())); const uint32_t timeout_ms = PROTOBUF_GET_MS_OR_DEFAULT(proto_config, timeout, 20); Filters::Common::RateLimit::ClientFactoryPtr client_factory = Filters::Common::RateLimit::rateLimitClientFactory(context); diff --git a/source/extensions/filters/http/ratelimit/ratelimit.cc b/source/extensions/filters/http/ratelimit/ratelimit.cc index 12aacde93b3f..20fbaee63c9a 100644 --- a/source/extensions/filters/http/ratelimit/ratelimit.cc +++ b/source/extensions/filters/http/ratelimit/ratelimit.cc @@ -127,17 +127,17 @@ void Filter::complete(Filters::Common::RateLimit::LimitStatus status, break; case Filters::Common::RateLimit::LimitStatus::OverLimit: cluster_->statsScope().counter("ratelimit.over_limit").inc(); - Http::CodeUtility::ResponseStatInfo info{config_->scope(), - cluster_->statsScope(), - EMPTY_STRING, - enumToInt(Http::Code::TooManyRequests), - true, - EMPTY_STRING, - EMPTY_STRING, - EMPTY_STRING, - EMPTY_STRING, - false}; - Http::CodeUtility::chargeResponseStat(info); + Http::CodeStats::ResponseStatInfo info{config_->scope(), + cluster_->statsScope(), + EMPTY_STRING, + enumToInt(Http::Code::TooManyRequests), + true, + EMPTY_STRING, + EMPTY_STRING, + EMPTY_STRING, + EMPTY_STRING, + false}; + httpContext().codeStats().chargeResponseStat(info); headers_to_add_->insertEnvoyRateLimited().value( Http::Headers::get().EnvoyRateLimitedValues.True); break; diff --git a/source/extensions/filters/http/ratelimit/ratelimit.h b/source/extensions/filters/http/ratelimit/ratelimit.h index f2e273cab2c5..5584a8fb6b59 100644 --- a/source/extensions/filters/http/ratelimit/ratelimit.h +++ b/source/extensions/filters/http/ratelimit/ratelimit.h @@ -6,6 +6,7 @@ #include #include "envoy/config/filter/http/rate_limit/v2/rate_limit.pb.h" +#include "envoy/http/context.h" #include "envoy/http/filter.h" #include "envoy/local_info/local_info.h" #include "envoy/ratelimit/ratelimit.h" @@ -35,7 +36,7 @@ class FilterConfig { public: FilterConfig(const envoy::config::filter::http::rate_limit::v2::RateLimit& config, const LocalInfo::LocalInfo& local_info, Stats::Scope& scope, - Runtime::Loader& runtime) + Runtime::Loader& runtime, Http::Context& http_context) : domain_(config.domain()), stage_(static_cast(config.stage())), request_type_(config.request_type().empty() ? stringToType("both") : stringToType(config.request_type())), @@ -44,7 +45,8 @@ class FilterConfig { rate_limited_grpc_status_( config.rate_limited_as_resource_exhausted() ? absl::make_optional(Grpc::Status::GrpcStatus::ResourceExhausted) - : absl::nullopt) {} + : absl::nullopt), + http_context_(http_context) {} const std::string& domain() const { return domain_; } const LocalInfo::LocalInfo& localInfo() const { return local_info_; } uint64_t stage() const { return stage_; } @@ -55,6 +57,7 @@ class FilterConfig { const absl::optional rateLimitedGrpcStatus() const { return rate_limited_grpc_status_; } + Http::Context& httpContext() { return http_context_; } private: static FilterRequestType stringToType(const std::string& request_type) { @@ -76,6 +79,7 @@ class FilterConfig { Runtime::Loader& runtime_; const bool failure_mode_deny_; const absl::optional rate_limited_grpc_status_; + Http::Context& http_context_; }; typedef std::shared_ptr FilterConfigSharedPtr; @@ -116,6 +120,7 @@ class Filter : public Http::StreamFilter, public Filters::Common::RateLimit::Req const Router::RouteEntry* route_entry, const Http::HeaderMap& headers) const; void addHeaders(Http::HeaderMap& headers); + Http::Context& httpContext() { return config_->httpContext(); } enum class State { NotStarted, Calling, Complete, Responded }; diff --git a/source/extensions/filters/network/http_connection_manager/config.cc b/source/extensions/filters/network/http_connection_manager/config.cc index a1621fd82f0e..6dd5ef35b878 100644 --- a/source/extensions/filters/network/http_connection_manager/config.cc +++ b/source/extensions/filters/network/http_connection_manager/config.cc @@ -96,7 +96,7 @@ HttpConnectionManagerFilterConfigFactory::createFilterFactoryFromProtoTyped( return [route_config_provider_manager, filter_config, &context, date_provider](Network::FilterManager& filter_manager) -> void { filter_manager.addReadFilter(Network::ReadFilterSharedPtr{new Http::ConnectionManagerImpl( - *filter_config, context.drainDecision(), context.random(), context.httpTracer(), + *filter_config, context.drainDecision(), context.random(), context.httpContext(), context.runtime(), context.localInfo(), context.clusterManager(), &context.overloadManager(), context.dispatcher().timeSystem())}); }; diff --git a/source/server/BUILD b/source/server/BUILD index 74c98023c797..e48cbc16555f 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -305,6 +305,8 @@ envoy_cc_library( "//source/common/config:bootstrap_json_lib", "//source/common/config:utility_lib", "//source/common/grpc:async_client_manager_lib", + "//source/common/http:codes_lib", + "//source/common/http:context_lib", "//source/common/local_info:local_info_lib", "//source/common/memory:stats_lib", "//source/common/protobuf:utility_lib", diff --git a/source/server/config_validation/BUILD b/source/server/config_validation/BUILD index bab593b37ae3..c0ac95f25d60 100644 --- a/source/server/config_validation/BUILD +++ b/source/server/config_validation/BUILD @@ -47,6 +47,7 @@ envoy_cc_library( ":async_client_lib", "//include/envoy/upstream:cluster_manager_interface", "//source/common/common:utility_lib", + "//source/common/http:context_lib", "//source/common/upstream:cluster_manager_lib", ], ) diff --git a/source/server/config_validation/cluster_manager.cc b/source/server/config_validation/cluster_manager.cc index 22ad6fb2c84d..dbf558e1e69e 100644 --- a/source/server/config_validation/cluster_manager.cc +++ b/source/server/config_validation/cluster_manager.cc @@ -9,18 +9,20 @@ ValidationClusterManagerFactory::ValidationClusterManagerFactory( Runtime::Loader& runtime, Stats::Store& stats, ThreadLocal::Instance& tls, Runtime::RandomGenerator& random, Network::DnsResolverSharedPtr dns_resolver, Ssl::ContextManager& ssl_context_manager, Event::Dispatcher& main_thread_dispatcher, - const LocalInfo::LocalInfo& local_info, Secret::SecretManager& secret_manager, Api::Api& api) + const LocalInfo::LocalInfo& local_info, Secret::SecretManager& secret_manager, Api::Api& api, + Http::Context& http_context) : ProdClusterManagerFactory(runtime, stats, tls, random, dns_resolver, ssl_context_manager, - main_thread_dispatcher, local_info, secret_manager, api) {} + main_thread_dispatcher, local_info, secret_manager, api, + http_context) {} ClusterManagerPtr ValidationClusterManagerFactory::clusterManagerFromProto( const envoy::config::bootstrap::v2::Bootstrap& bootstrap, Stats::Store& stats, ThreadLocal::Instance& tls, Runtime::Loader& runtime, Runtime::RandomGenerator& random, const LocalInfo::LocalInfo& local_info, AccessLog::AccessLogManager& log_manager, Server::Admin& admin) { - return ClusterManagerPtr{new ValidationClusterManager(bootstrap, *this, stats, tls, runtime, - random, local_info, log_manager, - main_thread_dispatcher_, admin, api_)}; + return std::make_unique( + bootstrap, *this, stats, tls, runtime, random, local_info, log_manager, + main_thread_dispatcher_, admin, api_, http_context_); } CdsApiPtr ValidationClusterManagerFactory::createCds( @@ -37,9 +39,9 @@ ValidationClusterManager::ValidationClusterManager( Stats::Store& stats, ThreadLocal::Instance& tls, Runtime::Loader& runtime, Runtime::RandomGenerator& random, const LocalInfo::LocalInfo& local_info, AccessLog::AccessLogManager& log_manager, Event::Dispatcher& main_thread_dispatcher, - Server::Admin& admin, Api::Api& api) + Server::Admin& admin, Api::Api& api, Http::Context& http_context) : ClusterManagerImpl(bootstrap, factory, stats, tls, runtime, random, local_info, log_manager, - main_thread_dispatcher, admin, api), + main_thread_dispatcher, admin, api, http_context), async_client_(main_thread_dispatcher.timeSystem()) {} Http::ConnectionPool::Instance* diff --git a/source/server/config_validation/cluster_manager.h b/source/server/config_validation/cluster_manager.h index 74b60532cad7..f030d8c2c13b 100644 --- a/source/server/config_validation/cluster_manager.h +++ b/source/server/config_validation/cluster_manager.h @@ -3,6 +3,7 @@ #include "envoy/secret/secret_manager.h" #include "envoy/upstream/cluster_manager.h" +#include "common/http/context_impl.h" #include "common/upstream/cluster_manager_impl.h" #include "server/config_validation/async_client.h" @@ -22,7 +23,8 @@ class ValidationClusterManagerFactory : public ProdClusterManagerFactory { Ssl::ContextManager& ssl_context_manager, Event::Dispatcher& main_thread_dispatcher, const LocalInfo::LocalInfo& local_info, - Secret::SecretManager& secret_manager, Api::Api& api); + Secret::SecretManager& secret_manager, Api::Api& api, + Http::Context& http_context); ClusterManagerPtr clusterManagerFromProto(const envoy::config::bootstrap::v2::Bootstrap& bootstrap, @@ -47,7 +49,7 @@ class ValidationClusterManager : public ClusterManagerImpl { ThreadLocal::Instance& tls, Runtime::Loader& runtime, Runtime::RandomGenerator& random, const LocalInfo::LocalInfo& local_info, AccessLog::AccessLogManager& log_manager, Event::Dispatcher& dispatcher, - Server::Admin& admin, Api::Api& api); + Server::Admin& admin, Api::Api& api, Http::Context& http_context); Http::ConnectionPool::Instance* httpConnPoolForCluster(const std::string&, ResourcePriority, Http::Protocol, diff --git a/source/server/config_validation/server.cc b/source/server/config_validation/server.cc index 92b41cc4cff4..37cd94dde6bc 100644 --- a/source/server/config_validation/server.cc +++ b/source/server/config_validation/server.cc @@ -89,8 +89,9 @@ void ValidationInstance::initialize(Options& options, ssl_context_manager_ = std::make_unique(time_system_); cluster_manager_factory_ = std::make_unique( runtime(), stats(), threadLocal(), random(), dnsResolver(), sslContextManager(), dispatcher(), - localInfo(), *secret_manager_, api()); + localInfo(), *secret_manager_, api(), http_context_); config_.initialize(bootstrap, *this, *cluster_manager_factory_); + http_context_.setTracer(config_.httpTracer()); clusterManager().setInitializedCb( [this]() -> void { init_manager_.initialize([]() -> void {}); }); } diff --git a/source/server/config_validation/server.h b/source/server/config_validation/server.h index a7606d65b62d..222c863e46e7 100644 --- a/source/server/config_validation/server.h +++ b/source/server/config_validation/server.h @@ -88,7 +88,7 @@ class ValidationInstance : Logger::Loggable, time_t startTimeCurrentEpoch() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } time_t startTimeFirstEpoch() override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } Stats::Store& stats() override { return stats_store_; } - Tracing::HttpTracer& httpTracer() override { return config_.httpTracer(); } + Http::Context& httpContext() override { return http_context_; } ThreadLocal::Instance& threadLocal() override { return thread_local_; } const LocalInfo::LocalInfo& localInfo() override { return *local_info_; } Event::TimeSystem& timeSystem() override { return time_system_; } @@ -155,7 +155,8 @@ class ValidationInstance : Logger::Loggable, std::unique_ptr listener_manager_; std::unique_ptr secret_manager_; std::unique_ptr overload_manager_; - Envoy::MutexTracer* mutex_tracer_; + MutexTracer* mutex_tracer_; + Http::ContextImpl http_context_; }; } // namespace Server diff --git a/source/server/http/admin.cc b/source/server/http/admin.cc index 63f0095c222c..15ad22d0019f 100644 --- a/source/server/http/admin.cc +++ b/source/server/http/admin.cc @@ -1033,7 +1033,7 @@ bool AdminImpl::createNetworkFilterChain(Network::Connection& connection, // Don't pass in the overload manager so that the admin interface is accessible even when // the envoy is overloaded. connection.addReadFilter(Network::ReadFilterSharedPtr{new Http::ConnectionManagerImpl( - *this, server_.drainManager(), server_.random(), server_.httpTracer(), server_.runtime(), + *this, server_.drainManager(), server_.random(), server_.httpContext(), server_.runtime(), server_.localInfo(), server_.clusterManager(), nullptr, server_.timeSystem())}); return true; } diff --git a/source/server/listener_manager_impl.h b/source/server/listener_manager_impl.h index 70f1f094b7af..42e2629c105b 100644 --- a/source/server/listener_manager_impl.h +++ b/source/server/listener_manager_impl.h @@ -119,6 +119,7 @@ class ListenerManagerImpl : public ListenerManager, Logger::LoggablestopListeners(); @@ -308,7 +307,7 @@ void InstanceImpl::initialize(Options& options, cluster_manager_factory_ = std::make_unique( runtime(), stats(), threadLocal(), random(), dnsResolver(), sslContextManager(), dispatcher(), - localInfo(), secretManager(), api()); + localInfo(), secretManager(), api(), http_context_); // Now the configuration gets parsed. The configuration may start setting // thread local data per above. See MainImpl::initialize() for why ConfigImpl diff --git a/source/server/server.h b/source/server/server.h index 3588e68c19a8..ec5f74bdfb17 100644 --- a/source/server/server.h +++ b/source/server/server.h @@ -19,6 +19,7 @@ #include "common/access_log/access_log_manager_impl.h" #include "common/common/logger_delegates.h" #include "common/grpc/async_client_manager_impl.h" +#include "common/http/context_impl.h" #include "common/runtime/runtime_impl.h" #include "common/secret/secret_manager_impl.h" #include "common/ssl/context_manager_impl.h" @@ -175,7 +176,7 @@ class InstanceImpl : Logger::Loggable, public Instance { time_t startTimeCurrentEpoch() override { return start_time_; } time_t startTimeFirstEpoch() override { return original_start_time_; } Stats::Store& stats() override { return stats_store_; } - Tracing::HttpTracer& httpTracer() override; + Http::Context& httpContext() override { return http_context_; } ThreadLocal::Instance& threadLocal() override { return thread_local_; } const LocalInfo::LocalInfo& localInfo() override { return *local_info_; } Event::TimeSystem& timeSystem() override { return time_system_; } @@ -235,6 +236,7 @@ class InstanceImpl : Logger::Loggable, public Instance { std::unique_ptr overload_manager_; std::unique_ptr run_helper_; Envoy::MutexTracer* mutex_tracer_; + Http::ContextImpl http_context_; }; } // namespace Server diff --git a/test/common/grpc/grpc_client_integration_test_harness.h b/test/common/grpc/grpc_client_integration_test_harness.h index 2c96c1560e2e..4ce94e8455c1 100644 --- a/test/common/grpc/grpc_client_integration_test_harness.h +++ b/test/common/grpc/grpc_client_integration_test_harness.h @@ -7,6 +7,7 @@ #include "common/grpc/async_client_impl.h" #include "common/grpc/google_async_client_impl.h" #include "common/http/async_client_impl.h" +#include "common/http/codes.h" #include "common/http/http2/conn_pool.h" #include "common/network/connection_impl.h" #include "common/network/raw_buffer_socket.h" @@ -274,7 +275,7 @@ class GrpcClientIntegrationTest : public GrpcClientIntegrationParamTest { .WillRepeatedly(Return(http_conn_pool_.get())); http_async_client_ = std::make_unique( cluster_info_ptr_, *stats_store_, dispatcher_, local_info_, cm_, runtime_, random_, - std::move(shadow_writer_ptr_)); + std::move(shadow_writer_ptr_), http_context_); EXPECT_CALL(cm_, httpAsyncClientForCluster(fake_cluster_name_)) .WillRepeatedly(ReturnRef(*http_async_client_)); EXPECT_CALL(cm_, get(fake_cluster_name_)).WillRepeatedly(Return(&thread_local_cluster_)); @@ -427,6 +428,7 @@ class GrpcClientIntegrationTest : public GrpcClientIntegrationParamTest { NiceMock random_; Http::AsyncClientPtr http_async_client_; Http::ConnectionPool::InstancePtr http_conn_pool_; + Http::ContextImpl http_context_; envoy::api::v2::core::Locality host_locality_; Upstream::MockHost* mock_host_ = new NiceMock(); Upstream::MockHostDescription* mock_host_description_ = diff --git a/test/common/http/BUILD b/test/common/http/BUILD index c59ef1da9c04..e17be6b31cfe 100644 --- a/test/common/http/BUILD +++ b/test/common/http/BUILD @@ -19,6 +19,7 @@ envoy_cc_test( ":common_lib", "//source/common/buffer:buffer_lib", "//source/common/http:async_client_lib", + "//source/common/http:context_lib", "//source/common/http:headers_lib", "//source/common/http:utility_lib", "//test/mocks:common_lib", @@ -124,6 +125,7 @@ envoy_cc_fuzz_test( ":conn_manager_impl_fuzz_proto_cc", "//source/common/common:empty_string", "//source/common/http:conn_manager_lib", + "//source/common/http:context_lib", "//source/common/http:date_provider_lib", "//source/common/network:address_lib", "//source/common/network:utility_lib", @@ -155,6 +157,7 @@ envoy_cc_test( "//source/common/common:macros", "//source/common/event:dispatcher_lib", "//source/common/http:conn_manager_lib", + "//source/common/http:context_lib", "//source/common/http:date_provider_lib", "//source/common/http:exception_lib", "//source/common/http:header_map_lib", diff --git a/test/common/http/async_client_impl_test.cc b/test/common/http/async_client_impl_test.cc index 31caae1d95a1..ba6115bedc04 100644 --- a/test/common/http/async_client_impl_test.cc +++ b/test/common/http/async_client_impl_test.cc @@ -5,6 +5,7 @@ #include "common/buffer/buffer_impl.h" #include "common/http/async_client_impl.h" +#include "common/http/context_impl.h" #include "common/http/headers.h" #include "common/http/utility.h" @@ -38,7 +39,7 @@ class AsyncClientImplTest : public testing::Test { AsyncClientImplTest() : client_(cm_.thread_local_cluster_.cluster_.info_, stats_store_, dispatcher_, local_info_, cm_, runtime_, random_, - Router::ShadowWriterPtr{new NiceMock()}) { + Router::ShadowWriterPtr{new NiceMock()}, http_context_) { message_->headers().insertMethod().value(std::string("GET")); message_->headers().insertHost().value(std::string("host")); message_->headers().insertPath().value(std::string("/")); @@ -72,6 +73,7 @@ class AsyncClientImplTest : public testing::Test { NiceMock random_; Stats::IsolatedStoreImpl stats_store_; NiceMock local_info_; + Http::ContextImpl http_context_; AsyncClientImpl client_; }; diff --git a/test/common/http/codes_speed_test.cc b/test/common/http/codes_speed_test.cc index 10ec27b23097..d59df3389ce0 100644 --- a/test/common/http/codes_speed_test.cc +++ b/test/common/http/codes_speed_test.cc @@ -24,11 +24,11 @@ class CodeUtilitySpeedTest { const std::string& request_vcluster_name = EMPTY_STRING, const std::string& from_az = EMPTY_STRING, const std::string& to_az = EMPTY_STRING) { - Http::CodeUtility::ResponseStatInfo info{ + Http::CodeStats::ResponseStatInfo info{ global_store_, cluster_scope_, "prefix.", code, internal_request, request_vhost_name, request_vcluster_name, from_az, to_az, canary}; - Http::CodeUtility::chargeResponseStat(info); + code_stats_.chargeResponseStat(info); } void addResponses() { @@ -44,15 +44,16 @@ class CodeUtilitySpeedTest { } void responseTiming() { - Http::CodeUtility::ResponseTimingInfo info{ + Http::CodeStats::ResponseTimingInfo info{ global_store_, cluster_scope_, "prefix.", std::chrono::milliseconds(5), true, true, "vhost_name", "req_vcluster_name", "from_az", "to_az"}; - Http::CodeUtility::chargeResponseTiming(info); + code_stats_.chargeResponseTiming(info); } Stats::IsolatedStoreImpl global_store_; Stats::IsolatedStoreImpl cluster_scope_; + Http::CodeStatsImpl code_stats_; }; } // namespace Http diff --git a/test/common/http/codes_test.cc b/test/common/http/codes_test.cc index a9127ee1d2d4..080ba84cd5ea 100644 --- a/test/common/http/codes_test.cc +++ b/test/common/http/codes_test.cc @@ -29,15 +29,16 @@ class CodeUtilityTest : public testing::Test { const std::string& request_vcluster_name = EMPTY_STRING, const std::string& from_az = EMPTY_STRING, const std::string& to_az = EMPTY_STRING) { - CodeUtility::ResponseStatInfo info{ + Http::CodeStats::ResponseStatInfo info{ global_store_, cluster_scope_, "prefix.", code, internal_request, request_vhost_name, request_vcluster_name, from_az, to_az, canary}; - CodeUtility::chargeResponseStat(info); + code_stats_.chargeResponseStat(info); } Stats::IsolatedStoreImpl global_store_; Stats::IsolatedStoreImpl cluster_scope_; + Http::CodeStatsImpl code_stats_; }; TEST_F(CodeUtilityTest, GroupStrings) { @@ -200,7 +201,7 @@ TEST(CodeUtilityResponseTimingTest, All) { Stats::MockStore global_store; Stats::MockStore cluster_scope; - CodeUtility::ResponseTimingInfo info{ + Http::CodeStats::ResponseTimingInfo info{ global_store, cluster_scope, "prefix.", std::chrono::milliseconds(5), true, true, "vhost_name", "req_vcluster_name", "from_az", "to_az"}; @@ -230,7 +231,34 @@ TEST(CodeUtilityResponseTimingTest, All) { EXPECT_CALL(cluster_scope, deliverHistogramToSinks( Property(&Stats::Metric::name, "prefix.zone.from_az.to_az.upstream_rq_time"), 5)); - CodeUtility::chargeResponseTiming(info); + Http::CodeStatsImpl code_stats; + code_stats.chargeResponseTiming(info); +} + +class CodeStatsTest : public testing::Test { +protected: + absl::string_view stripTrailingDot(absl::string_view prefix) { + return CodeStatsImpl::stripTrailingDot(prefix); + } + + std::string join(const std::vector& v) { return CodeStatsImpl::join(v); } + + CodeStatsImpl code_stats_; +}; + +TEST_F(CodeStatsTest, StripTrailingDot) { + EXPECT_EQ("", stripTrailingDot("")); + EXPECT_EQ("foo", stripTrailingDot("foo.")); + EXPECT_EQ(".foo", stripTrailingDot(".foo")); // no change + EXPECT_EQ("foo.", stripTrailingDot("foo..")); // only one dot gets stripped. +} + +TEST_F(CodeStatsTest, Join) { + EXPECT_EQ("hello.world", join({"hello", "world"})); + EXPECT_EQ("hello.world", join({"", "hello", "world"})); // leading empty token ignored. + EXPECT_EQ("hello.", join({"hello", ""})); // trailign empty token not ignored. + EXPECT_EQ("hello", join({"hello"})); + EXPECT_EQ("", join({""})); } } // namespace Http diff --git a/test/common/http/conn_manager_impl_fuzz_test.cc b/test/common/http/conn_manager_impl_fuzz_test.cc index 3c4695d92e90..e8afb9b66db1 100644 --- a/test/common/http/conn_manager_impl_fuzz_test.cc +++ b/test/common/http/conn_manager_impl_fuzz_test.cc @@ -14,6 +14,7 @@ // * Fuzz config settings #include "common/common/empty_string.h" #include "common/http/conn_manager_impl.h" +#include "common/http/context_impl.h" #include "common/http/date_provider_impl.h" #include "common/http/exception.h" #include "common/network/address_impl.h" @@ -382,7 +383,7 @@ DEFINE_PROTO_FUZZER(const test::common::http::ConnManagerImplTestCase& input) { FuzzConfig config; NiceMock drain_close; NiceMock random; - NiceMock tracer; + Http::ContextImpl http_context; NiceMock runtime; NiceMock local_info; NiceMock cluster_manager; @@ -399,7 +400,7 @@ DEFINE_PROTO_FUZZER(const test::common::http::ConnManagerImplTestCase& input) { filter_callbacks.connection_.remote_address_ = std::make_shared("0.0.0.0"); - ConnectionManagerImpl conn_manager(config, drain_close, random, tracer, runtime, local_info, + ConnectionManagerImpl conn_manager(config, drain_close, random, http_context, runtime, local_info, cluster_manager, nullptr, config.time_system_); conn_manager.initializeReadFilterCallbacks(filter_callbacks); diff --git a/test/common/http/conn_manager_impl_test.cc b/test/common/http/conn_manager_impl_test.cc index f691758bd51d..6dac2394a849 100644 --- a/test/common/http/conn_manager_impl_test.cc +++ b/test/common/http/conn_manager_impl_test.cc @@ -15,6 +15,7 @@ #include "common/common/empty_string.h" #include "common/common/macros.h" #include "common/http/conn_manager_impl.h" +#include "common/http/context_impl.h" #include "common/http/date_provider_impl.h" #include "common/http/exception.h" #include "common/http/header_map_impl.h" @@ -87,6 +88,8 @@ class HttpConnectionManagerImplTest : public testing::Test, public ConnectionMan tracing_stats_{CONN_MAN_TRACING_STATS(POOL_COUNTER(fake_stats_))}, listener_stats_{CONN_MAN_LISTENER_STATS(POOL_COUNTER(fake_listener_stats_))} { + http_context_.setTracer(tracer_); + // response_encoder_ is not a NiceMock on purpose. This prevents complaining about this // method only. EXPECT_CALL(response_encoder_, getStream()).Times(AtLeast(0)); @@ -110,7 +113,7 @@ class HttpConnectionManagerImplTest : public testing::Test, public ConnectionMan filter_callbacks_.connection_.remote_address_ = std::make_shared("0.0.0.0"); conn_manager_ = std::make_unique( - *this, drain_close_, random_, tracer_, runtime_, local_info_, cluster_manager_, + *this, drain_close_, random_, http_context_, runtime_, local_info_, cluster_manager_, &overload_manager_, test_time_.timeSystem()); conn_manager_->initializeReadFilterCallbacks(filter_callbacks_); @@ -256,6 +259,7 @@ class HttpConnectionManagerImplTest : public testing::Test, public ConnectionMan DangerousDeprecatedTestTime test_time_; RouteConfigProvider route_config_provider_; NiceMock tracer_; + Http::ContextImpl http_context_; NiceMock runtime_; NiceMock log_manager_; std::string access_log_path_; diff --git a/test/common/router/BUILD b/test/common/router/BUILD index cd9c2cd16e7f..3394cbd55fbd 100644 --- a/test/common/router/BUILD +++ b/test/common/router/BUILD @@ -154,6 +154,7 @@ envoy_cc_test( srcs = ["router_test.cc"], deps = [ "//source/common/buffer:buffer_lib", + "//source/common/http:context_lib", "//source/common/network:utility_lib", "//source/common/router:router_lib", "//source/common/upstream:upstream_includes", diff --git a/test/common/router/router_test.cc b/test/common/router/router_test.cc index 7077eb39fdbd..9af87291aa8f 100644 --- a/test/common/router/router_test.cc +++ b/test/common/router/router_test.cc @@ -6,6 +6,7 @@ #include "common/common/empty_string.h" #include "common/config/metadata.h" #include "common/config/well_known_names.h" +#include "common/http/context_impl.h" #include "common/network/utility.h" #include "common/router/config_impl.h" #include "common/router/router.h" @@ -77,7 +78,7 @@ class RouterTestBase : public testing::Test { : shadow_writer_(new MockShadowWriter()), config_("test.", local_info_, stats_store_, cm_, runtime_, random_, ShadowWriterPtr{shadow_writer_}, true, start_child_span, suppress_envoy_headers, - test_time_.timeSystem()), + test_time_.timeSystem(), http_context_), router_(config_) { router_.setDecoderFilterCallbacks(callbacks_); upstream_locality_.set_zone("to_az"); @@ -189,6 +190,7 @@ class RouterTestBase : public testing::Test { NiceMock runtime_; NiceMock random_; Http::ConnectionPool::MockCancellable cancellable_; + Http::ContextImpl http_context_; NiceMock callbacks_; MockShadowWriter* shadow_writer_; NiceMock local_info_; diff --git a/test/common/upstream/cluster_manager_impl_test.cc b/test/common/upstream/cluster_manager_impl_test.cc index 5cb734145dee..3f31a87e5f3a 100644 --- a/test/common/upstream/cluster_manager_impl_test.cc +++ b/test/common/upstream/cluster_manager_impl_test.cc @@ -8,6 +8,7 @@ #include "common/api/api_impl.h" #include "common/config/bootstrap_json.h" #include "common/config/utility.h" +#include "common/http/context_impl.h" #include "common/network/socket_option_impl.h" #include "common/network/transport_socket_options_impl.h" #include "common/network/utility.h" @@ -149,7 +150,7 @@ class TestClusterManagerImpl : public ClusterManagerImpl { Event::Dispatcher& main_thread_dispatcher, Server::Admin& admin, Api::Api& api, MockLocalClusterUpdate& local_cluster_update) : ClusterManagerImpl(bootstrap, factory, stats, tls, runtime, random, local_info, log_manager, - main_thread_dispatcher, admin, api), + main_thread_dispatcher, admin, api, http_context_), local_cluster_update_(local_cluster_update) {} protected: @@ -158,6 +159,7 @@ class TestClusterManagerImpl : public ClusterManagerImpl { const HostVector& hosts_removed) override { local_cluster_update_.post(priority, hosts_added, hosts_removed); } + Http::ContextImpl http_context_; MockLocalClusterUpdate& local_cluster_update_; }; @@ -176,7 +178,7 @@ class ClusterManagerImplTest : public testing::Test { void create(const envoy::config::bootstrap::v2::Bootstrap& bootstrap) { cluster_manager_ = std::make_unique( bootstrap, factory_, factory_.stats_, factory_.tls_, factory_.runtime_, factory_.random_, - factory_.local_info_, log_manager_, factory_.dispatcher_, admin_, *api_); + factory_.local_info_, log_manager_, factory_.dispatcher_, admin_, *api_, http_context_); } void createWithLocalClusterUpdate(const bool enable_merge_window = true) { @@ -253,6 +255,7 @@ class ClusterManagerImplTest : public testing::Test { NiceMock admin_; Event::SimulatedTimeSystem time_system_; MockLocalClusterUpdate local_cluster_update_; + Http::ContextImpl http_context_; }; envoy::config::bootstrap::v2::Bootstrap parseBootstrapFromJson(const std::string& json_string) { diff --git a/test/config_test/config_test.cc b/test/config_test/config_test.cc index 93eab2cf3c72..d121873ecd85 100644 --- a/test/config_test/config_test.cc +++ b/test/config_test/config_test.cc @@ -58,7 +58,7 @@ class ConfigTest { cluster_manager_factory_ = std::make_unique( server_.runtime(), server_.stats(), server_.threadLocal(), server_.random(), server_.dnsResolver(), ssl_context_manager_, server_.dispatcher(), server_.localInfo(), - server_.secretManager(), *api_); + server_.secretManager(), *api_, server_.httpContext()); ON_CALL(server_, clusterManager()).WillByDefault(Invoke([&]() -> Upstream::ClusterManager& { return *main_config.clusterManager(); diff --git a/test/extensions/filters/http/ext_authz/BUILD b/test/extensions/filters/http/ext_authz/BUILD index 0692b53be3c3..8c8185c6d807 100644 --- a/test/extensions/filters/http/ext_authz/BUILD +++ b/test/extensions/filters/http/ext_authz/BUILD @@ -20,6 +20,7 @@ envoy_extension_cc_test( "//source/common/buffer:buffer_lib", "//source/common/common:empty_string", "//source/common/config:filter_json_lib", + "//source/common/http:context_lib", "//source/common/http:headers_lib", "//source/common/json:json_loader_lib", "//source/common/network:address_lib", diff --git a/test/extensions/filters/http/ext_authz/ext_authz_test.cc b/test/extensions/filters/http/ext_authz/ext_authz_test.cc index 39543888c6ac..6b311ee5701e 100644 --- a/test/extensions/filters/http/ext_authz/ext_authz_test.cc +++ b/test/extensions/filters/http/ext_authz/ext_authz_test.cc @@ -8,6 +8,7 @@ #include "common/buffer/buffer_impl.h" #include "common/common/empty_string.h" +#include "common/http/context_impl.h" #include "common/http/headers.h" #include "common/json/json_loader.h" #include "common/network/address_impl.h" @@ -83,6 +84,11 @@ class HttpExtAuthzFilterTestBase { public: HttpExtAuthzFilterTestBase() {} + void initConfig(envoy::config::filter::http::ext_authz::v2alpha::ExtAuthz& proto_config) { + config_ = std::make_unique(proto_config, local_info_, stats_store_, runtime_, cm_, + http_context_); + } + FilterConfigSharedPtr config_; Filters::Common::ExtAuthz::MockClient* client_; std::unique_ptr filter_; @@ -96,6 +102,7 @@ class HttpExtAuthzFilterTestBase { NiceMock local_info_; Network::Address::InstanceConstSharedPtr addr_; NiceMock connection_; + Http::ContextImpl http_context_; void prepareCheck() { ON_CALL(filter_callbacks_, connection()).WillByDefault(Return(&connection_)); @@ -111,7 +118,7 @@ class HttpExtAuthzFilterTest : public testing::Test, public HttpExtAuthzFilterTe void initialize(const std::string yaml) { envoy::config::filter::http::ext_authz::v2alpha::ExtAuthz proto_config{}; MessageUtil::loadFromYaml(yaml, proto_config); - config_.reset(new FilterConfig(proto_config, local_info_, stats_store_, runtime_, cm_)); + initConfig(proto_config); client_ = new Filters::Common::ExtAuthz::MockClient(); filter_ = std::make_unique(config_, Filters::Common::ExtAuthz::ClientPtr{client_}); @@ -134,7 +141,7 @@ class HttpExtAuthzFilterParamTest : public TestWithParam(config_, Filters::Common::ExtAuthz::ClientPtr{client_}); diff --git a/test/extensions/filters/http/ratelimit/BUILD b/test/extensions/filters/http/ratelimit/BUILD index 12f6b49bb1aa..38922688bff5 100644 --- a/test/extensions/filters/http/ratelimit/BUILD +++ b/test/extensions/filters/http/ratelimit/BUILD @@ -19,6 +19,7 @@ envoy_extension_cc_test( "//source/common/buffer:buffer_lib", "//source/common/common:empty_string", "//source/common/config:filter_json_lib", + "//source/common/http:context_lib", "//source/common/http:headers_lib", "//source/extensions/filters/common/ratelimit:ratelimit_lib", "//source/extensions/filters/http/ratelimit:ratelimit_lib", diff --git a/test/extensions/filters/http/ratelimit/ratelimit_test.cc b/test/extensions/filters/http/ratelimit/ratelimit_test.cc index 66b67ba470d8..197fe61008e4 100644 --- a/test/extensions/filters/http/ratelimit/ratelimit_test.cc +++ b/test/extensions/filters/http/ratelimit/ratelimit_test.cc @@ -5,6 +5,7 @@ #include "common/buffer/buffer_impl.h" #include "common/common/empty_string.h" #include "common/config/filter_json.h" +#include "common/http/context_impl.h" #include "common/http/headers.h" #include "extensions/filters/http/ratelimit/ratelimit.h" @@ -51,7 +52,8 @@ class HttpRateLimitFilterTest : public testing::Test { envoy::config::filter::http::rate_limit::v2::RateLimit proto_config{}; MessageUtil::loadFromYaml(yaml, proto_config); - config_.reset(new FilterConfig(proto_config, local_info_, stats_store_, runtime_)); + config_.reset( + new FilterConfig(proto_config, local_info_, stats_store_, runtime_, http_context_)); client_ = new Filters::Common::RateLimit::MockClient(); filter_ = std::make_unique(config_, Filters::Common::RateLimit::ClientPtr{client_}); @@ -89,6 +91,7 @@ class HttpRateLimitFilterTest : public testing::Test { NiceMock vh_rate_limit_; std::vector descriptor_{{{{"descriptor_key", "descriptor_value"}}}}; NiceMock local_info_; + Http::ContextImpl http_context_; }; TEST_F(HttpRateLimitFilterTest, BadConfig) { diff --git a/test/mocks/server/BUILD b/test/mocks/server/BUILD index 6ae32489c405..48201b814075 100644 --- a/test/mocks/server/BUILD +++ b/test/mocks/server/BUILD @@ -26,6 +26,7 @@ envoy_cc_mock( "//include/envoy/server:worker_interface", "//include/envoy/ssl:context_manager_interface", "//include/envoy/upstream:health_checker_interface", + "//source/common/http:context_lib", "//source/common/secret:secret_manager_impl_lib", "//source/common/singleton:manager_impl_lib", "//source/common/ssl:context_lib", diff --git a/test/mocks/server/mocks.cc b/test/mocks/server/mocks.cc index dde5059bde62..89e44cd3fbd5 100644 --- a/test/mocks/server/mocks.cc +++ b/test/mocks/server/mocks.cc @@ -124,7 +124,7 @@ MockInstance::MockInstance() ssl_context_manager_(timeSystem()), singleton_manager_(new Singleton::ManagerImpl()) { ON_CALL(*this, threadLocal()).WillByDefault(ReturnRef(thread_local_)); ON_CALL(*this, stats()).WillByDefault(ReturnRef(stats_store_)); - ON_CALL(*this, httpTracer()).WillByDefault(ReturnRef(http_tracer_)); + ON_CALL(*this, httpContext()).WillByDefault(ReturnRef(http_context_)); ON_CALL(*this, dnsResolver()).WillByDefault(Return(dns_resolver_)); ON_CALL(*this, api()).WillByDefault(ReturnRef(api_)); ON_CALL(*this, admin()).WillByDefault(ReturnRef(admin_)); @@ -165,7 +165,6 @@ MockFactoryContext::MockFactoryContext() : singleton_manager_(new Singleton::Man ON_CALL(*this, clusterManager()).WillByDefault(ReturnRef(cluster_manager_)); ON_CALL(*this, dispatcher()).WillByDefault(ReturnRef(dispatcher_)); ON_CALL(*this, drainDecision()).WillByDefault(ReturnRef(drain_manager_)); - ON_CALL(*this, httpTracer()).WillByDefault(ReturnRef(http_tracer_)); ON_CALL(*this, initManager()).WillByDefault(ReturnRef(init_manager_)); ON_CALL(*this, localInfo()).WillByDefault(ReturnRef(local_info_)); ON_CALL(*this, random()).WillByDefault(ReturnRef(random_)); diff --git a/test/mocks/server/mocks.h b/test/mocks/server/mocks.h index f97a92fdd94d..2463b9ab1400 100644 --- a/test/mocks/server/mocks.h +++ b/test/mocks/server/mocks.h @@ -21,6 +21,7 @@ #include "envoy/stats/stats_options.h" #include "envoy/thread/thread.h" +#include "common/http/context_impl.h" #include "common/secret/secret_manager_impl.h" #include "common/ssl/context_manager_impl.h" @@ -336,10 +337,9 @@ class MockInstance : public Instance { MOCK_METHOD0(startTimeCurrentEpoch, time_t()); MOCK_METHOD0(startTimeFirstEpoch, time_t()); MOCK_METHOD0(stats, Stats::Store&()); - MOCK_METHOD0(httpTracer, Tracing::HttpTracer&()); + MOCK_METHOD0(httpContext, Http::Context&()); MOCK_METHOD0(threadLocal, ThreadLocal::Instance&()); MOCK_METHOD0(localInfo, const LocalInfo::LocalInfo&()); - // MOCK_METHOD0(timeSystem, Event::TestTimeSystem&()); MOCK_CONST_METHOD0(statsFlushInterval, std::chrono::milliseconds()); Event::TestTimeSystem& timeSystem() override { return test_time_.timeSystem(); } @@ -347,7 +347,6 @@ class MockInstance : public Instance { std::unique_ptr secret_manager_; testing::NiceMock thread_local_; Stats::IsolatedStoreImpl stats_store_; - testing::NiceMock http_tracer_; std::shared_ptr> dns_resolver_{ new testing::NiceMock()}; testing::NiceMock api_; @@ -368,6 +367,7 @@ class MockInstance : public Instance { testing::NiceMock listener_manager_; testing::NiceMock overload_manager_; Singleton::ManagerPtr singleton_manager_; + Http::ContextImpl http_context_; }; namespace Configuration { @@ -418,6 +418,8 @@ class MockFactoryContext : public FactoryContext { MOCK_METHOD0(timeSource, TimeSource&()); Event::SimulatedTimeSystem& timeSystem() { return time_system_; } + Http::Context& httpContext() override { return http_context_; } + testing::NiceMock access_log_manager_; testing::NiceMock cluster_manager_; testing::NiceMock dispatcher_; @@ -434,6 +436,8 @@ class MockFactoryContext : public FactoryContext { Stats::IsolatedStoreImpl listener_scope_; Event::SimulatedTimeSystem time_system_; testing::NiceMock overload_manager_; + Tracing::HttpNullTracer null_tracer_; + Http::ContextImpl http_context_; }; class MockTransportSocketFactoryContext : public TransportSocketFactoryContext { diff --git a/test/server/BUILD b/test/server/BUILD index 5055ead4ec35..1225f24718a4 100644 --- a/test/server/BUILD +++ b/test/server/BUILD @@ -31,6 +31,7 @@ envoy_cc_test( deps = [ "//source/common/api:api_lib", "//source/common/event:dispatcher_lib", + "//source/common/http:context_lib", "//source/common/upstream:cluster_manager_lib", "//source/extensions/stat_sinks/statsd:config", "//source/extensions/transport_sockets/raw_buffer:config", diff --git a/test/server/config_validation/cluster_manager_test.cc b/test/server/config_validation/cluster_manager_test.cc index 0216bb3033fb..1163da347ac5 100644 --- a/test/server/config_validation/cluster_manager_test.cc +++ b/test/server/config_validation/cluster_manager_test.cc @@ -2,6 +2,7 @@ #include "envoy/upstream/upstream.h" #include "common/api/api_impl.h" +#include "common/http/context_impl.h" #include "common/ssl/context_manager_impl.h" #include "server/config_validation/cluster_manager.h" @@ -35,10 +36,11 @@ TEST(ValidationClusterManagerTest, MockedMethods) { NiceMock dispatcher; LocalInfo::MockLocalInfo local_info; NiceMock admin; + Http::ContextImpl http_context; ValidationClusterManagerFactory factory(runtime, stats_store, tls, random, dns_resolver, ssl_context_manager, dispatcher, local_info, - secret_manager, *api); + secret_manager, *api, http_context); AccessLog::MockAccessLogManager log_manager; const envoy::config::bootstrap::v2::Bootstrap bootstrap; diff --git a/test/server/configuration_impl_test.cc b/test/server/configuration_impl_test.cc index b5c5691c1770..26cfa1aa3e39 100644 --- a/test/server/configuration_impl_test.cc +++ b/test/server/configuration_impl_test.cc @@ -54,10 +54,10 @@ class ConfigurationImplTest : public testing::Test { protected: ConfigurationImplTest() : api_(Api::createApiForTest(stats_store_)), - cluster_manager_factory_(server_.runtime(), server_.stats(), server_.threadLocal(), - server_.random(), server_.dnsResolver(), - server_.sslContextManager(), server_.dispatcher(), - server_.localInfo(), server_.secretManager(), *api_) {} + cluster_manager_factory_( + server_.runtime(), server_.stats(), server_.threadLocal(), server_.random(), + server_.dnsResolver(), server_.sslContextManager(), server_.dispatcher(), + server_.localInfo(), server_.secretManager(), *api_, server_.httpContext()) {} Stats::IsolatedStoreImpl stats_store_; Api::ApiPtr api_;