Skip to content

Commit

Permalink
Pass regexp filter to /stats/prometheus (#7182)
Browse files Browse the repository at this point in the history
Signed-off-by: Daishan Peng <daishan@rancher.com>
  • Loading branch information
StrongMonkey authored and mattklein123 committed Jun 11, 2019
1 parent ed3274f commit 6ea29c7
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 26 deletions.
24 changes: 15 additions & 9 deletions source/server/http/admin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,13 @@ void populateFallbackResponseHeaders(Http::Code code, Http::HeaderMap& header_ma
header_map.addReference(headers.XContentTypeOptions, headers.XContentTypeOptionValues.Nosniff);
}

// Helper method to get filter parameter
absl::optional<std::regex> filterParam(Http::Utility::QueryParams params) {
return (params.find("filter") != params.end())
? absl::optional<std::regex>{std::regex(params.at("filter"))}
: absl::nullopt;
}

// Helper method that ensures that we've setting flags based on all the health flag values on the
// host.
void setHealthFlag(Upstream::Host::HealthFlag flag, const Upstream::Host& host,
Expand Down Expand Up @@ -696,10 +703,7 @@ Http::Code AdminImpl::handlerStats(absl::string_view url, Http::HeaderMap& respo

const bool used_only = params.find("usedonly") != params.end();
const bool has_format = !(params.find("format") == params.end());
const absl::optional<std::regex> regex =
(params.find("filter") != params.end())
? absl::optional<std::regex>{std::regex(params.at("filter"))}
: absl::nullopt;
const absl::optional<std::regex> regex = filterParam(params);

std::map<std::string, uint64_t> all_stats;
for (const Stats::CounterSharedPtr& counter : server_.stats().counters()) {
Expand Down Expand Up @@ -753,8 +757,10 @@ Http::Code AdminImpl::handlerPrometheusStats(absl::string_view path_and_query, H
Buffer::Instance& response, AdminStream&) {
const Http::Utility::QueryParams params = Http::Utility::parseQueryString(path_and_query);
const bool used_only = params.find("usedonly") != params.end();
const absl::optional<std::regex> regex = filterParam(params);
PrometheusStatsFormatter::statsAsPrometheus(server_.stats().counters(), server_.stats().gauges(),
server_.stats().histograms(), response, used_only);
server_.stats().histograms(), response, used_only,
regex);
return Http::Code::OK;
}

Expand Down Expand Up @@ -788,10 +794,10 @@ uint64_t PrometheusStatsFormatter::statsAsPrometheus(
const std::vector<Stats::CounterSharedPtr>& counters,
const std::vector<Stats::GaugeSharedPtr>& gauges,
const std::vector<Stats::ParentHistogramSharedPtr>& histograms, Buffer::Instance& response,
const bool used_only) {
const bool used_only, const absl::optional<std::regex>& regex) {
std::unordered_set<std::string> metric_type_tracker;
for (const auto& counter : counters) {
if (!shouldShowMetric(counter, used_only)) {
if (!shouldShowMetric(counter, used_only, regex)) {
continue;
}

Expand All @@ -805,7 +811,7 @@ uint64_t PrometheusStatsFormatter::statsAsPrometheus(
}

for (const auto& gauge : gauges) {
if (!shouldShowMetric(gauge, used_only)) {
if (!shouldShowMetric(gauge, used_only, regex)) {
continue;
}

Expand All @@ -819,7 +825,7 @@ uint64_t PrometheusStatsFormatter::statsAsPrometheus(
}

for (const auto& histogram : histograms) {
if (!shouldShowMetric(histogram, used_only)) {
if (!shouldShowMetric(histogram, used_only, regex)) {
continue;
}

Expand Down
10 changes: 7 additions & 3 deletions source/server/http/admin.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ class AdminImpl : public Admin,
bool used_only,
const absl::optional<std::regex> regex = absl::nullopt,
bool pretty_print = false);

static std::string
runtimeAsJson(const std::vector<std::pair<std::string, Runtime::Snapshot::Entry>>& entries);
std::vector<const UrlHandler*> sortedHandlers() const;
Expand Down Expand Up @@ -413,7 +414,8 @@ class PrometheusStatsFormatter {
static uint64_t statsAsPrometheus(const std::vector<Stats::CounterSharedPtr>& counters,
const std::vector<Stats::GaugeSharedPtr>& gauges,
const std::vector<Stats::ParentHistogramSharedPtr>& histograms,
Buffer::Instance& response, const bool used_only);
Buffer::Instance& response, const bool used_only,
const absl::optional<std::regex>& regex);
/**
* Format the given tags, returning a string as a comma-separated list
* of <tag_name>="<tag_value>" pairs.
Expand All @@ -434,8 +436,10 @@ class PrometheusStatsFormatter {
* Determine whether a metric has never been emitted and choose to
* not show it if we only wanted used metrics.
*/
static bool shouldShowMetric(const std::shared_ptr<Stats::Metric>& metric, const bool used_only) {
return !used_only || metric->used();
static bool shouldShowMetric(const std::shared_ptr<Stats::Metric>& metric, const bool used_only,
const absl::optional<std::regex>& regex) {
return ((!used_only || metric->used()) &&
(!regex.has_value() || std::regex_search(metric->name(), regex.value())));
}
};

Expand Down
58 changes: 44 additions & 14 deletions test/server/http/admin_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1391,8 +1391,8 @@ TEST_F(PrometheusStatsFormatterTest, MetricNameCollison) {
{{"another_tag_name_4", "another_tag_4-value"}});

Buffer::OwnedImpl response;
auto size =
PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, false);
auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response,
false, absl::nullopt);
EXPECT_EQ(2UL, size);
}

Expand All @@ -1411,8 +1411,8 @@ TEST_F(PrometheusStatsFormatterTest, UniqueMetricName) {
{{"another_tag_name_4", "another_tag_4-value"}});

Buffer::OwnedImpl response;
auto size =
PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, false);
auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response,
false, absl::nullopt);
EXPECT_EQ(4UL, size);
}

Expand All @@ -1430,8 +1430,8 @@ TEST_F(PrometheusStatsFormatterTest, HistogramWithNoValuesAndNoTags) {
addHistogram(histogram);

Buffer::OwnedImpl response;
auto size =
PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, false);
auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response,
false, absl::nullopt);
EXPECT_EQ(1UL, size);

const std::string expected_output = R"EOF(# TYPE envoy_histogram1 histogram
Expand Down Expand Up @@ -1483,8 +1483,8 @@ TEST_F(PrometheusStatsFormatterTest, HistogramWithHighCounts) {
addHistogram(histogram);

Buffer::OwnedImpl response;
auto size =
PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, false);
auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response,
false, absl::nullopt);
EXPECT_EQ(1UL, size);

const std::string expected_output = R"EOF(# TYPE envoy_histogram1 histogram
Expand Down Expand Up @@ -1535,8 +1535,8 @@ TEST_F(PrometheusStatsFormatterTest, OutputWithAllMetricTypes) {
.WillOnce(testing::ReturnRef(h1_cumulative_statistics));

Buffer::OwnedImpl response;
auto size =
PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, false);
auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response,
false, absl::nullopt);
EXPECT_EQ(5UL, size);

const std::string expected_output = R"EOF(# TYPE envoy_cluster_test_1_upstream_cx_total counter
Expand Down Expand Up @@ -1595,8 +1595,8 @@ TEST_F(PrometheusStatsFormatterTest, OutputWithUsedOnly) {
.WillOnce(testing::ReturnRef(h1_cumulative_statistics));

Buffer::OwnedImpl response;
auto size =
PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response, true);
auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_, response,
true, absl::nullopt);
EXPECT_EQ(1UL, size);

const std::string expected_output = R"EOF(# TYPE envoy_cluster_test_1_upstream_rq_time histogram
Expand Down Expand Up @@ -1645,7 +1645,7 @@ TEST_F(PrometheusStatsFormatterTest, OutputWithUsedOnlyHistogram) {

Buffer::OwnedImpl response;
auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_,
response, used_only);
response, used_only, absl::nullopt);
EXPECT_EQ(0UL, size);
}

Expand All @@ -1656,10 +1656,40 @@ TEST_F(PrometheusStatsFormatterTest, OutputWithUsedOnlyHistogram) {

Buffer::OwnedImpl response;
auto size = PrometheusStatsFormatter::statsAsPrometheus(counters_, gauges_, histograms_,
response, used_only);
response, used_only, absl::nullopt);
EXPECT_EQ(1UL, size);
}
}

TEST_F(PrometheusStatsFormatterTest, OutputWithRegexp) {
addCounter("cluster.test_1.upstream_cx_total", {{"a.tag-name", "a.tag-value"}});
addCounter("cluster.test_2.upstream_cx_total", {{"another_tag_name", "another_tag-value"}});
addGauge("cluster.test_3.upstream_cx_total", {{"another_tag_name_3", "another_tag_3-value"}});
addGauge("cluster.test_4.upstream_cx_total", {{"another_tag_name_4", "another_tag_4-value"}});

const std::vector<uint64_t> h1_values = {50, 20, 30, 70, 100, 5000, 200};
HistogramWrapper h1_cumulative;
h1_cumulative.setHistogramValues(h1_values);
Stats::HistogramStatisticsImpl h1_cumulative_statistics(h1_cumulative.getHistogram());

auto histogram1 = std::make_shared<NiceMock<Stats::MockParentHistogram>>();
histogram1->name_ = "cluster.test_1.upstream_rq_time";
histogram1->setTags({Stats::Tag{"key1", "value1"}, Stats::Tag{"key2", "value2"}});
addHistogram(histogram1);

Buffer::OwnedImpl response;
auto size = PrometheusStatsFormatter::statsAsPrometheus(
counters_, gauges_, histograms_, response, false,
absl::optional<std::regex>{std::regex("cluster.test_1.upstream_cx_total")});
EXPECT_EQ(1UL, size);

const std::string expected_output =
R"EOF(# TYPE envoy_cluster_test_1_upstream_cx_total counter
envoy_cluster_test_1_upstream_cx_total{a_tag_name="a.tag-value"} 0
)EOF";

EXPECT_EQ(expected_output, response.toString());
}

} // namespace Server
} // namespace Envoy

0 comments on commit 6ea29c7

Please sign in to comment.