Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/server/admin/stats_handler.cc
Line
Count
Source (jump to first uncovered line)
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
5.34k
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
5.34k
Admin::UrlHandler StatsHandler::statsHandler(bool active_mode) {
177
5.34k
  Admin::ParamDescriptor usedonly{
178
5.34k
      Admin::ParamDescriptor::Type::Boolean, "usedonly",
179
5.34k
      "Only include stats that have been written by system since restart"};
180
5.34k
  Admin::ParamDescriptor histogram_buckets{Admin::ParamDescriptor::Type::Enum,
181
5.34k
                                           "histogram_buckets",
182
5.34k
                                           "Histogram bucket display mode",
183
5.34k
                                           {"cumulative", "disjoint", "detailed", "none"}};
184
5.34k
  Admin::ParamDescriptor format{Admin::ParamDescriptor::Type::Enum,
185
5.34k
                                "format",
186
5.34k
                                "Format to use",
187
5.34k
                                {"html", "active-html", "text", "json"}};
188
5.34k
  Admin::ParamDescriptor filter{Admin::ParamDescriptor::Type::String, "filter",
189
5.34k
                                "Regular expression (Google re2) for filtering stats"};
190
5.34k
  Admin::ParamDescriptor type{Admin::ParamDescriptor::Type::Enum,
191
5.34k
                              "type",
192
5.34k
                              "Stat types to include.",
193
5.34k
                              {StatLabels::All, StatLabels::Counters, StatLabels::Histograms,
194
5.34k
                               StatLabels::Gauges, StatLabels::TextReadouts}};
195
196
5.34k
  Admin::ParamDescriptorVec params{usedonly, filter};
197
5.34k
  if (!active_mode) {
198
5.34k
    params.push_back(format);
199
5.34k
  }
200
5.34k
  params.push_back(type);
201
5.34k
  if (!active_mode) {
202
5.34k
    params.push_back(histogram_buckets);
203
5.34k
  }
204
205
5.34k
  return {
206
5.34k
      "/stats",
207
5.34k
      "print server stats",
208
5.34k
      [this](AdminStream& admin_stream) -> Admin::RequestPtr { return makeRequest(admin_stream); },
209
5.34k
      false,
210
5.34k
      false,
211
5.34k
      params};
212
5.34k
}
213
214
} // namespace Server
215
} // namespace Envoy