LCOV - code coverage report
Current view: top level - source/server/admin - stats_handler.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 36 143 25.2 %
Date: 2024-01-05 06:35:25 Functions: 2 17 11.8 %

          Line data    Source code
       1             : #include "source/server/admin/stats_handler.h"
       2             : 
       3             : #include <functional>
       4             : #include <vector>
       5             : 
       6             : #include "envoy/admin/v3/mutex_stats.pb.h"
       7             : #include "envoy/server/admin.h"
       8             : 
       9             : #include "source/common/buffer/buffer_impl.h"
      10             : #include "source/common/common/empty_string.h"
      11             : #include "source/common/http/headers.h"
      12             : #include "source/common/http/utility.h"
      13             : #include "source/server/admin/prometheus_stats.h"
      14             : #include "source/server/admin/stats_request.h"
      15             : 
      16             : #include "absl/strings/numbers.h"
      17             : 
      18             : namespace Envoy {
      19             : namespace Server {
      20             : 
      21             : const uint64_t RecentLookupsCapacity = 100;
      22             : 
      23         134 : StatsHandler::StatsHandler(Server::Instance& server) : HandlerContextBase(server) {}
      24             : 
      25             : Http::Code StatsHandler::handlerResetCounters(Http::ResponseHeaderMap&, Buffer::Instance& response,
      26           0 :                                               AdminStream&) {
      27           0 :   for (const Stats::CounterSharedPtr& counter : server_.stats().counters()) {
      28           0 :     counter->reset();
      29           0 :   }
      30           0 :   server_.stats().symbolTable().clearRecentLookups();
      31           0 :   response.add("OK\n");
      32           0 :   return Http::Code::OK;
      33           0 : }
      34             : 
      35             : Http::Code StatsHandler::handlerStatsRecentLookups(Http::ResponseHeaderMap&,
      36           0 :                                                    Buffer::Instance& response, AdminStream&) {
      37           0 :   Stats::SymbolTable& symbol_table = server_.stats().symbolTable();
      38           0 :   std::string table;
      39           0 :   const uint64_t total =
      40           0 :       symbol_table.getRecentLookups([&table](absl::string_view name, uint64_t count) {
      41           0 :         table += fmt::format("{:8d} {}\n", count, name);
      42           0 :       });
      43           0 :   if (table.empty() && symbol_table.recentLookupCapacity() == 0) {
      44           0 :     table = "Lookup tracking is not enabled. Use /stats/recentlookups/enable to enable.\n";
      45           0 :   } else {
      46           0 :     response.add("   Count Lookup\n");
      47           0 :   }
      48           0 :   response.add(absl::StrCat(table, "\ntotal: ", total, "\n"));
      49           0 :   return Http::Code::OK;
      50           0 : }
      51             : 
      52             : Http::Code StatsHandler::handlerStatsRecentLookupsClear(Http::ResponseHeaderMap&,
      53           0 :                                                         Buffer::Instance& response, AdminStream&) {
      54           0 :   server_.stats().symbolTable().clearRecentLookups();
      55           0 :   response.add("OK\n");
      56           0 :   return Http::Code::OK;
      57           0 : }
      58             : 
      59             : Http::Code StatsHandler::handlerStatsRecentLookupsDisable(Http::ResponseHeaderMap&,
      60             :                                                           Buffer::Instance& response,
      61           0 :                                                           AdminStream&) {
      62           0 :   server_.stats().symbolTable().setRecentLookupCapacity(0);
      63           0 :   response.add("OK\n");
      64           0 :   return Http::Code::OK;
      65           0 : }
      66             : 
      67             : Http::Code StatsHandler::handlerStatsRecentLookupsEnable(Http::ResponseHeaderMap&,
      68           0 :                                                          Buffer::Instance& response, AdminStream&) {
      69           0 :   server_.stats().symbolTable().setRecentLookupCapacity(RecentLookupsCapacity);
      70           0 :   response.add("OK\n");
      71           0 :   return Http::Code::OK;
      72           0 : }
      73             : 
      74           0 : Admin::RequestPtr StatsHandler::makeRequest(AdminStream& admin_stream) {
      75           0 :   StatsParams params;
      76           0 :   Buffer::OwnedImpl response;
      77           0 :   Http::Code code = params.parse(admin_stream.getRequestHeaders().getPathValue(), response);
      78           0 :   if (code != Http::Code::OK) {
      79           0 :     return Admin::makeStaticTextRequest(response, code);
      80           0 :   }
      81             : 
      82           0 :   if (params.format_ == StatsFormat::Prometheus) {
      83             :     // TODO(#16139): modify streaming algorithm to cover Prometheus.
      84             :     //
      85             :     // This may be easiest to accomplish by populating the set
      86             :     // with tagExtractedName(), and allowing for vectors of
      87             :     // stats as multiples will have the same tag-extracted names.
      88             :     // Ideally we'd find a way to do this without slowing down
      89             :     // the non-Prometheus implementations.
      90           0 :     Buffer::OwnedImpl response;
      91           0 :     prometheusFlushAndRender(params, response);
      92           0 :     return Admin::makeStaticTextRequest(response, code);
      93           0 :   }
      94             : 
      95           0 :   if (server_.statsConfig().flushOnAdmin()) {
      96           0 :     server_.flushStats();
      97           0 :   }
      98             : 
      99           0 :   bool active_mode;
     100           0 : #ifdef ENVOY_ADMIN_HTML
     101           0 :   active_mode = params.format_ == StatsFormat::ActiveHtml;
     102             : #else
     103             :   active_mode = false;
     104             : #endif
     105           0 :   return makeRequest(
     106           0 :       server_.stats(), params, server_.clusterManager(),
     107           0 :       [this, active_mode]() -> Admin::UrlHandler { return statsHandler(active_mode); });
     108           0 : }
     109             : 
     110             : Admin::RequestPtr StatsHandler::makeRequest(Stats::Store& stats, const StatsParams& params,
     111             :                                             const Upstream::ClusterManager& cluster_manager,
     112           0 :                                             StatsRequest::UrlHandlerFn url_handler_fn) {
     113           0 :   return std::make_unique<StatsRequest>(stats, params, cluster_manager, url_handler_fn);
     114           0 : }
     115             : 
     116             : Http::Code StatsHandler::handlerPrometheusStats(Http::ResponseHeaderMap&,
     117             :                                                 Buffer::Instance& response,
     118           0 :                                                 AdminStream& admin_stream) {
     119           0 :   return prometheusStats(admin_stream.getRequestHeaders().getPathValue(), response);
     120           0 : }
     121             : 
     122             : Http::Code StatsHandler::prometheusStats(absl::string_view path_and_query,
     123           0 :                                          Buffer::Instance& response) {
     124           0 :   StatsParams params;
     125           0 :   Http::Code code = params.parse(path_and_query, response);
     126           0 :   if (code != Http::Code::OK) {
     127           0 :     return code;
     128           0 :   }
     129             : 
     130           0 :   if (server_.statsConfig().flushOnAdmin()) {
     131           0 :     server_.flushStats();
     132           0 :   }
     133             : 
     134           0 :   prometheusFlushAndRender(params, response);
     135           0 :   return Http::Code::OK;
     136           0 : }
     137             : 
     138           0 : void StatsHandler::prometheusFlushAndRender(const StatsParams& params, Buffer::Instance& response) {
     139           0 :   if (server_.statsConfig().flushOnAdmin()) {
     140           0 :     server_.flushStats();
     141           0 :   }
     142           0 :   prometheusRender(server_.stats(), server_.api().customStatNamespaces(), server_.clusterManager(),
     143           0 :                    params, response);
     144           0 : }
     145             : 
     146             : void StatsHandler::prometheusRender(Stats::Store& stats,
     147             :                                     const Stats::CustomStatNamespaces& custom_namespaces,
     148             :                                     const Upstream::ClusterManager& cluster_manager,
     149           0 :                                     const StatsParams& params, Buffer::Instance& response) {
     150           0 :   const std::vector<Stats::TextReadoutSharedPtr>& text_readouts_vec =
     151           0 :       params.prometheus_text_readouts_ ? stats.textReadouts()
     152           0 :                                        : std::vector<Stats::TextReadoutSharedPtr>();
     153           0 :   PrometheusStatsFormatter::statsAsPrometheus(stats.counters(), stats.gauges(), stats.histograms(),
     154           0 :                                               text_readouts_vec, cluster_manager, response, params,
     155           0 :                                               custom_namespaces);
     156           0 : }
     157             : 
     158             : Http::Code StatsHandler::handlerContention(Http::ResponseHeaderMap& response_headers,
     159           0 :                                            Buffer::Instance& response, AdminStream&) {
     160             : 
     161           0 :   if (server_.options().mutexTracingEnabled() && server_.mutexTracer() != nullptr) {
     162           0 :     response_headers.setReferenceContentType(Http::Headers::get().ContentTypeValues.Json);
     163             : 
     164           0 :     envoy::admin::v3::MutexStats mutex_stats;
     165           0 :     mutex_stats.set_num_contentions(server_.mutexTracer()->numContentions());
     166           0 :     mutex_stats.set_current_wait_cycles(server_.mutexTracer()->currentWaitCycles());
     167           0 :     mutex_stats.set_lifetime_wait_cycles(server_.mutexTracer()->lifetimeWaitCycles());
     168           0 :     response.add(MessageUtil::getJsonStringFromMessageOrError(mutex_stats, true, true));
     169           0 :   } else {
     170           0 :     response.add("Mutex contention tracing is not enabled. To enable, run Envoy with flag "
     171           0 :                  "--enable-mutex-tracing.");
     172           0 :   }
     173           0 :   return Http::Code::OK;
     174           0 : }
     175             : 
     176         134 : Admin::UrlHandler StatsHandler::statsHandler(bool active_mode) {
     177         134 :   Admin::ParamDescriptor usedonly{
     178         134 :       Admin::ParamDescriptor::Type::Boolean, "usedonly",
     179         134 :       "Only include stats that have been written by system since restart"};
     180         134 :   Admin::ParamDescriptor histogram_buckets{Admin::ParamDescriptor::Type::Enum,
     181         134 :                                            "histogram_buckets",
     182         134 :                                            "Histogram bucket display mode",
     183         134 :                                            {"cumulative", "disjoint", "detailed", "none"}};
     184         134 :   Admin::ParamDescriptor format{Admin::ParamDescriptor::Type::Enum,
     185         134 :                                 "format",
     186         134 :                                 "Format to use",
     187         134 :                                 {"html", "active-html", "text", "json"}};
     188         134 :   Admin::ParamDescriptor filter{Admin::ParamDescriptor::Type::String, "filter",
     189         134 :                                 "Regular expression (Google re2) for filtering stats"};
     190         134 :   Admin::ParamDescriptor type{Admin::ParamDescriptor::Type::Enum,
     191         134 :                               "type",
     192         134 :                               "Stat types to include.",
     193         134 :                               {StatLabels::All, StatLabels::Counters, StatLabels::Histograms,
     194         134 :                                StatLabels::Gauges, StatLabels::TextReadouts}};
     195             : 
     196         134 :   Admin::ParamDescriptorVec params{usedonly, filter};
     197         134 :   if (!active_mode) {
     198         134 :     params.push_back(format);
     199         134 :   }
     200         134 :   params.push_back(type);
     201         134 :   if (!active_mode) {
     202         134 :     params.push_back(histogram_buckets);
     203         134 :   }
     204             : 
     205         134 :   return {
     206         134 :       "/stats",
     207         134 :       "print server stats",
     208         134 :       [this](AdminStream& admin_stream) -> Admin::RequestPtr { return makeRequest(admin_stream); },
     209         134 :       false,
     210         134 :       false,
     211         134 :       params};
     212         134 : }
     213             : 
     214             : } // namespace Server
     215             : } // namespace Envoy

Generated by: LCOV version 1.15