Line data Source code
1 : #pragma once 2 : 3 : #include <chrono> 4 : #include <cstdint> 5 : #include <string> 6 : 7 : #include "envoy/http/codes.h" 8 : #include "envoy/http/header_map.h" 9 : #include "envoy/stats/scope.h" 10 : 11 : #include "source/common/common/thread.h" 12 : #include "source/common/stats/symbol_table.h" 13 : 14 : namespace Envoy { 15 : namespace Http { 16 : 17 : struct CodeStats::ResponseStatInfo { 18 : Stats::Scope& global_scope_; 19 : Stats::Scope& cluster_scope_; 20 : Stats::StatName prefix_; 21 : uint64_t response_status_code_; 22 : bool internal_request_; 23 : Stats::StatName request_vhost_name_; 24 : Stats::StatName request_vcluster_name_; 25 : Stats::StatName request_route_name_; 26 : Stats::StatName from_zone_; 27 : Stats::StatName to_zone_; 28 : bool upstream_canary_; 29 : }; 30 : 31 : struct CodeStats::ResponseTimingInfo { 32 : Stats::Scope& global_scope_; 33 : Stats::Scope& cluster_scope_; 34 : Stats::StatName prefix_; 35 : std::chrono::milliseconds response_time_; 36 : bool upstream_canary_; 37 : bool internal_request_; 38 : Stats::StatName request_vhost_name_; 39 : Stats::StatName request_vcluster_name_; 40 : Stats::StatName request_route_name_; 41 : Stats::StatName from_zone_; 42 : Stats::StatName to_zone_; 43 : }; 44 : 45 : class CodeStatsImpl : public CodeStats { 46 : public: 47 : explicit CodeStatsImpl(Stats::SymbolTable& symbol_table); 48 : 49 : // CodeStats 50 : void chargeBasicResponseStat(Stats::Scope& scope, Stats::StatName prefix, Code response_code, 51 : bool exclude_http_code_stats) const override; 52 : void chargeResponseStat(const ResponseStatInfo& info, 53 : bool exclude_http_code_stats) const override; 54 : void chargeResponseTiming(const ResponseTimingInfo& info) const override; 55 : 56 : private: 57 : friend class CodeStatsTest; 58 : 59 : void writeCategory(const ResponseStatInfo& info, Stats::StatName rq_group, 60 : Stats::StatName rq_code, Stats::StatName category) const; 61 : void incCounter(Stats::Scope& scope, const Stats::StatNameVec& names) const; 62 : void incCounter(Stats::Scope& scope, Stats::StatName a, Stats::StatName b) const; 63 : void recordHistogram(Stats::Scope& scope, const Stats::StatNameVec& names, 64 : Stats::Histogram::Unit unit, uint64_t count) const; 65 : 66 : Stats::StatName upstreamRqGroup(Code response_code) const; 67 : Stats::StatName upstreamRqStatName(Code response_code) const; 68 : 69 : mutable Stats::StatNamePool stat_name_pool_; 70 : Stats::SymbolTable& symbol_table_; 71 : 72 : const Stats::StatName canary_; 73 : const Stats::StatName empty_; // Used for the group-name for invalid http codes. 74 : const Stats::StatName external_; 75 : const Stats::StatName internal_; 76 : const Stats::StatName upstream_; 77 : const Stats::StatName upstream_rq_1xx_; 78 : const Stats::StatName upstream_rq_2xx_; 79 : const Stats::StatName upstream_rq_3xx_; 80 : const Stats::StatName upstream_rq_4xx_; 81 : const Stats::StatName upstream_rq_5xx_; 82 : const Stats::StatName upstream_rq_unknown_; 83 : const Stats::StatName upstream_rq_completed_; 84 : const Stats::StatName upstream_rq_time_; 85 : const Stats::StatName vcluster_; 86 : const Stats::StatName vhost_; 87 : const Stats::StatName route_; 88 : const Stats::StatName zone_; 89 : 90 : // Use an array of atomic pointers to hold StatNameStorage objects for 91 : // every conceivable HTTP response code. In the hot-path we'll reference 92 : // these with a null-check, and if we need to allocate a symbol for a 93 : // new code, we'll take a mutex to avoid duplicate allocations and 94 : // subsequent leaks. This is similar in principle to a ReaderMutexLock, 95 : // but should be faster, as ReaderMutexLocks appear to be too expensive for 96 : // fine-grained controls. Another option would be to use a lock per 97 : // stat-name, which might have similar performance to atomics with default 98 : // barrier policy. 99 : // 100 : // We don't allocate these all up front during construction because 101 : // SymbolTable greedily encodes the first 128 names it discovers in one 102 : // byte. We don't want those high-value single-byte codes to go to fully 103 : // enumerating the 4 prefixes combined with HTTP codes that are seldom used, 104 : // so we allocate these on demand. 105 : // 106 : // There can be multiple symbol tables in a server. The one passed into the 107 : // Codes constructor should be the same as the one passed to 108 : // Stats::ThreadLocalStore. Note that additional symbol tables can be created 109 : // from IsolatedStoreImpl's default constructor. 110 : // 111 : // The Codes object is global to the server. 112 : 113 : static constexpr uint32_t NumHttpCodes = 500; 114 : static constexpr uint32_t HttpCodeOffset = 100; // code 100 is at index 0. 115 : mutable Thread::AtomicPtrArray<const uint8_t, NumHttpCodes, 116 : Thread::AtomicPtrAllocMode::DoNotDelete> 117 : rc_stat_names_; 118 : }; 119 : 120 : /** 121 : * General utility routines for HTTP codes. 122 : */ 123 : class CodeUtility { 124 : public: 125 : /** 126 : * Convert an HTTP response code to a descriptive string. 127 : * @param code supplies the code to convert. 128 : * @return const char* the string. 129 : */ 130 : static const char* toString(Code code); 131 : 132 1047 : static bool is1xx(uint64_t code) { return code >= 100 && code < 200; } 133 561 : static bool is2xx(uint64_t code) { return code >= 200 && code < 300; } 134 379 : static bool is3xx(uint64_t code) { return code >= 300 && code < 400; } 135 177 : static bool is4xx(uint64_t code) { return code >= 400 && code < 500; } 136 484 : static bool is5xx(uint64_t code) { return code >= 500 && code < 600; } 137 : 138 0 : static bool isGatewayError(uint64_t code) { return code >= 502 && code < 505; } 139 : 140 : static std::string groupStringForResponseCode(Code response_code); 141 : }; 142 : 143 : } // namespace Http 144 : } // namespace Envoy