Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass regexp filter to /stats/prometheus #7182

Merged
merged 2 commits into from
Jun 11, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: const absl::optional<std::regex>&

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, updated!

/**
* 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