[COMMIT seastar master] Merge 'Add an API for the metrics layer to manipulate metrics dynamically.' from Amnon Heiman

3 views
Skip to first unread message

Commit Bot

<bot@cloudius-systems.com>
unread,
Jan 29, 2023, 11:31:06 AM1/29/23
to seastar-dev@googlegroups.com, Avi Kivity
From: Avi Kivity <a...@scylladb.com>
Committer: Avi Kivity <a...@scylladb.com>
Branch: master

Merge 'Add an API for the metrics layer to manipulate metrics dynamically.' from Amnon Heiman

It is typical for software that builds on top of Seastar report per-shard metrics.
With modern hardware, this can quickly grow to a large number of metrics that
overload the reporting system and the collecting server.

One of the main issues around metrics reduction is that many of the metrics are only
helpful in certain situations.

It will be best to have the option to add metrics freely and choose in runtime what to report.

Changing label values lets a metrics-collecting server (e.g., Prometheus) ask for only some of the metrics.

Disabling and enabling the metrics will ensure they will not be calculated and reported at all, but the
configuration will need to be changed when required.

This series adds an option to perform metrics manipulation dynamically. It includes adding, removing, and changing labels and also Enable, disable metrics, and enable and disable the skip_when_empty option.

The general logic follows Prometheus metrics_relabel_config configuration.

The relabel config is a vector of rules applied one after the other. Rules can be changed at any point, it would first update all the existing metrics, and then any new metrics will be updated according to the rules.

Here are a few examples:

To add a level label with a value 1, to the reactor_utilization metric:
```
std::vector<sm::relabel_config> rl(1);
rl[0].source_labels = {"__name__"};
rl[0].target_label = "level";
rl[0].replacement = "1";
rl[0].expr = "reactor_utilization";
set_relabel_configs(rl);
```

To report only the metrics with level label equals 1:
```
std::vector<sm::relabel_config> rl(2);
rl[0].source_labels = {"__name__"};
rl[0].action = sm::relabel_config::relabel_action::drop;

rl[1].source_labels = {"level"};
rl[1].expr = "1";
rl[1].action = sm::relabel_config::relabel_action::keep;
set_relabel_configs(rl);
```

Closes #1347

* github.com:scylladb/seastar:
Adding relabel config tests
Add an API for the metrics layer to manipulate metrics dynamically.

---
diff --git a/include/seastar/core/metrics_api.hh b/include/seastar/core/metrics_api.hh
--- a/include/seastar/core/metrics_api.hh
+++ b/include/seastar/core/metrics_api.hh
@@ -25,6 +25,7 @@
#include <unordered_map>
#include <seastar/core/sharded.hh>
#include <boost/functional/hash.hpp>
+
/*!
* \file metrics_api.hh
* \brief header file for metric API layer (like prometheus or collectd)
@@ -60,6 +61,23 @@ struct hash<seastar::metrics::impl::labels_type> {

namespace seastar {
namespace metrics {
+struct relabel_config;
+
+/*!
+ * \brief result of metric relabeling
+ *
+ * The result of calling set_relabel_configs.
+ *
+ * metrics_relabeled_due_to_collision the number of metrics that caused conflict
+ * and were relabeled to avoid name collision.
+ *
+ * Non zero value indicates there were name collisions.
+ *
+ */
+struct metric_relabeling_result {
+ size_t metrics_relabeled_due_to_collision;
+};
+
namespace impl {

/**
@@ -104,6 +122,9 @@ public:
const labels_type& labels() const {
return _labels;
}
+ labels_type& labels() {
+ return _labels;
+ }
sstring full_name() const;

bool operator<(const metric_id&) const;
@@ -161,6 +182,7 @@ struct metric_family_info {
*/
struct metric_info {
metric_id id;
+ labels_type original_labels;
bool enabled;
skip_when_empty should_skip_when_empty;
};
@@ -210,6 +232,9 @@ public:
const metric_info& info() const {
return _info;
}
+ metric_info& info() {
+ return _info;
+ }
metric_function& get_function() {
return _f;
}
@@ -326,6 +351,7 @@ class impl {
shared_ptr<metric_metadata> _metadata;
std::set<sstring> _labels;
std::vector<std::vector<metric_function>> _current_metrics;
+ std::vector<relabel_config> _relabel_configs;
public:
value_map& get_value_map() {
return _value_map;
@@ -360,6 +386,12 @@ public:
const std::set<sstring>& get_labels() const noexcept {
return _labels;
}
+
+ future<metric_relabeling_result> set_relabel_configs(const std::vector<relabel_config>& relabel_configs);
+
+ const std::vector<relabel_config>& get_relabel_configs() const noexcept {
+ return _relabel_configs;
+ }
};

const value_map& get_value_map();
@@ -396,5 +428,57 @@ struct options : public program_options::option_group {
*/
future<> configure(const options& opts);

+/*!
+ * \brief Perform relabeling and operation on metrics dynamically.
+ *
+ * The function would return true if the changes were applied with no conflict
+ * or false, if there was a conflict in the registration.
+ *
+ * The general logic follows Prometheus metrics_relabel_config configuration.
+ * The relabel rules are applied one after the other.
+ * You can add or change a label. you can enable or disable a metric,
+ * in that case the metrics will not be reported at all.
+ * You can turn on and off the skip_when_empty flag.
+ *
+ * Using the Prometheus convention, the metric name is __name__.
+ * Names cannot be changed.
+ *
+ * Import notes:
+ * - The relabeling always starts from the original set of labels the metric
+ * was created with.
+ * - calling with an empty set will remove the relabel config and will
+ * return all metrics to their original labels
+ * - To prevent a situation that calling this function would crash the system.
+ * in a situation where a conflicting metrics name are entered, an additional label
+ * will be added to the labels with a unique ID.
+ *
+ * A few examples:
+ * To add a level label with a value 1, to the reactor_utilization metric:
+ * std::vector<sm::relabel_config> rl(1);
+ rl[0].source_labels = {"__name__"};
+ rl[0].target_label = "level";
+ rl[0].replacement = "1";
+ rl[0].expr = "reactor_utilization";
+ set_relabel_configs(rl);
+ *
+ * To report only the metrics with the level label equals 1
+ *
+ std::vector<sm::relabel_config> rl(2);
+ rl[0].source_labels = {"__name__"};
+ rl[0].action = sm::relabel_config::relabel_action::drop;
+
+ rl[1].source_labels = {"level"};
+ rl[1].expr = "1";
+ rl[1].action = sm::relabel_config::relabel_action::keep;
+ set_relabel_configs(rl);
+
+ */
+future<metric_relabeling_result> set_relabel_configs(const std::vector<relabel_config>& relabel_configs);
+/*
+ * \brief return the current relabel_configs
+ * This function returns a vector of the current relabel configs
+ */
+const std::vector<relabel_config>& get_relabel_configs();
+
}
}
diff --git a/include/seastar/core/relabel_config.hh b/include/seastar/core/relabel_config.hh
--- a/include/seastar/core/relabel_config.hh
+++ b/include/seastar/core/relabel_config.hh
@@ -0,0 +1,101 @@
+/*
+ * This file is open source software, licensed to you under the terms
+ * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
+ * distributed with this work for additional information regarding copyright
+ * ownership. You may not use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Copyright 2022 ScyllaDB
+ */
+#include <regex>
+
+namespace seastar {
+namespace metrics {
+
+/*!
+ * \brief a wrapper class around regex with the original expr
+ *
+ * regex does not contain the original expression, this wrapper class
+ * acts both as a string and as a regex.
+ */
+class relabel_config_regex {
+ std::string _regex_str;
+ std::regex _regex;
+public:
+ relabel_config_regex() = default;
+ relabel_config_regex(const std::string& expr) : _regex_str(expr), _regex(std::regex(expr)) {}
+ relabel_config_regex(const char* expr) : _regex_str(expr), _regex(std::regex(expr)) {}
+ const std::string& str() const noexcept {
+ return _regex_str;
+ }
+ const std::regex& regex() const noexcept {
+ return _regex;
+ }
+
+ relabel_config_regex& operator=(const char* expr) {
+ std::string str(expr);
+ return operator=(str);
+ }
+
+ relabel_config_regex& operator=(const std::string& expr) {
+ _regex_str = expr;
+ _regex = std::regex(_regex_str);
+ return *this;
+ }
+};
+
+/*!
+ * \brief a relabel_config allows changing metrics labels dynamically
+ *
+ * The logic is similar to Prometheus configuration
+ * This is how Prometheus entry looks like:
+ * - source_labels: [version]
+ regex: '([0-9]+\.[0-9]+)(\.?[0-9]*).*'
+ replacement: '$1$2'
+ target_label: svr
+ * relabel_action values:
+ * skip_when_empty - when set supported metrics (histogram, summary and counters)
+ * will not be reported if they were never used.
+ * report_when_empty - revert the skip_when_empty flag
+ * replace - replace the value of the target_label
+ * keep - enable the metrics
+ * drop - disable the metrics
+ * drop_label - remove the target label
+ *
+ * source_labels - a list of source labels, the labels are concatenated
+ * with the separator and and the combine value is match to the regex.
+ * target_label - the labels to perform the action on when replacing a value or when dropping a label.
+ * replacement - the string to use when replacing a label value, regex group can be used.
+ * expr - a regular expression in a string format. Action would be taken if the regex
+ * match the concatenated labels.
+ * action - The action to perform when there is a match.
+ * separator - separator to use when concatenating the labels.
+ *
+ */
+struct relabel_config {
+ enum class relabel_action {skip_when_empty, report_when_empty, replace, keep, drop, drop_label};
+ std::vector<std::string> source_labels;
+ std::string target_label;
+ std::string replacement = "${1}";
+ relabel_config_regex expr = "(.*)";
+ relabel_action action = relabel_action::replace;
+ std::string separator = ";";
+};
+
+/*!
+ * \brief a helper function to translate a string to relabel_config::relabel_action enum values
+ */
+relabel_config::relabel_action relabel_config_action(const std::string& action);
+}
+}
diff --git a/src/core/metrics.cc b/src/core/metrics.cc
--- a/src/core/metrics.cc
+++ b/src/core/metrics.cc
@@ -21,13 +21,16 @@

#include <seastar/core/metrics.hh>
#include <seastar/core/metrics_api.hh>
+#include <seastar/core/relabel_config.hh>
#include <seastar/core/reactor.hh>
#include <boost/range/algorithm.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/range/algorithm_ext/erase.hpp>
+#include <random>

namespace seastar {
+extern seastar::logger seastar_logger;
namespace metrics {

double_registration::double_registration(std::string what): std::runtime_error(what) {}
@@ -109,12 +112,81 @@ future<> configure(const options& opts) {
});
}

+future<metric_relabeling_result> set_relabel_configs(const std::vector<relabel_config>& relabel_configs) {
+ return impl::get_local_impl()->set_relabel_configs(relabel_configs);
+}
+
+const std::vector<relabel_config>& get_relabel_configs() {
+ return impl::get_local_impl()->get_relabel_configs();
+}
+
+
+static bool apply_relabeling(const relabel_config& rc, impl::metric_info& info) {
+ std::stringstream s;
+ bool first = true;
+ for (auto&& l: rc.source_labels) {
+ auto val = info.id.labels().find(l);
+ if (l != "__name__" && val == info.id.labels().end()) {
+ //If not all the labels are found nothing todo
+ return false;
+ }
+ if (first) {
+ first = false;
+ } else {
+ s << rc.separator;
+ }
+ s << ((l == "__name__") ? info.id.full_name() : val->second);
+ }
+ std::smatch match;
+ // regex_search forbid temporary strings
+ std::string tmps = s.str();
+ if (!std::regex_search(tmps, match, rc.expr.regex())) {
+ return false;
+ }
+
+ switch (rc.action) {
+ case relabel_config::relabel_action::drop:
+ case relabel_config::relabel_action::keep: {
+ info.enabled = rc.action == relabel_config::relabel_action::keep;
+ return true;
+ }
+ case relabel_config::relabel_action::report_when_empty:
+ case relabel_config::relabel_action::skip_when_empty: {
+ info.should_skip_when_empty = (rc.action == relabel_config::relabel_action::skip_when_empty) ? skip_when_empty::yes : skip_when_empty::no;
+ return false;
+ }
+ case relabel_config::relabel_action::drop_label: {
+ if (info.id.labels().find(rc.target_label) != info.id.labels().end()) {
+ info.id.labels().erase(rc.target_label);
+ }
+ return true;
+ };
+ case relabel_config::relabel_action::replace: {
+ if (!rc.target_label.empty()) {
+ std::string fmt_s = match.format(rc.replacement);
+ info.id.labels()[rc.target_label] = fmt_s;
+ }
+ return true;
+ }
+ default:
+ break;
+ }
+ return true;
+}

bool label_instance::operator!=(const label_instance& id2) const {
auto& id1 = *this;
return !(id1 == id2);
}

+/*!
+ * \brief get_unique_id generate a random id
+ */
+static std::string get_unique_id() {
+ std::random_device rd;
+ return std::to_string(rd()) + "-" + std::to_string(rd()) + "-" + std::to_string(rd()) + "-" + std::to_string(rd());
+}
+
label shard_label("shard");
namespace impl {

@@ -123,6 +195,7 @@ registered_metric::registered_metric(metric_id id, metric_function f, bool enabl
_info.enabled = enabled;
_info.should_skip_when_empty = skip;
_info.id = id;
+ _info.original_labels = id.labels();
}

metric_value metric_value::operator+(const metric_value& c) {
@@ -349,17 +422,21 @@ std::vector<std::vector<metric_function>>& impl::functions() {

void impl::add_registration(const metric_id& id, const metric_type& type, metric_function f, const description& d, bool enabled, skip_when_empty skip, const std::vector<std::string>& aggregate_labels) {
auto rm = ::seastar::make_shared<registered_metric>(id, f, enabled, skip);
+ for (auto&& rl : _relabel_configs) {
+ apply_relabeling(rl, rm->info());
+ }
+
sstring name = id.full_name();
if (_value_map.find(name) != _value_map.end()) {
auto& metric = _value_map[name];
- if (metric.find(id.labels()) != metric.end()) {
+ if (metric.find(rm->info().id.labels()) != metric.end()) {
throw double_registration("registering metrics twice for metrics: " + name);
}
if (metric.info().type != type.base_type) {
throw std::runtime_error("registering metrics " + name + " registered with different type.");
}
- metric[id.labels()] = rm;
- for (auto&& i : id.labels()) {
+ metric[rm->info().id.labels()] = rm;
+ for (auto&& i : rm->info().id.labels()) {
_labels.insert(i.first);
}
} else {
@@ -368,15 +445,76 @@ void impl::add_registration(const metric_id& id, const metric_type& type, metric
_value_map[name].info().inherit_type = type.type_name;
_value_map[name].info().name = id.full_name();
_value_map[name].info().aggregate_labels = aggregate_labels;
- _value_map[name][id.labels()] = rm;
+ _value_map[name][rm->info().id.labels()] = rm;
}
dirty();
}

+future<metric_relabeling_result> impl::set_relabel_configs(const std::vector<relabel_config>& relabel_configs) {
+ _relabel_configs = relabel_configs;
+ metric_relabeling_result conflicts{0};
+ for (auto&& family : _value_map) {
+ std::vector<shared_ptr<registered_metric>> rms;
+ for (auto&& metric = family.second.begin(); metric != family.second.end();) {
+ metric->second->info().id.labels().clear();
+ metric->second->info().id.labels() = metric->second->info().original_labels;
+ for (auto rl : _relabel_configs) {
+ if (apply_relabeling(rl, metric->second->info())) {
+ dirty();
+ }
+ }
+ if (metric->first != metric->second->info().id.labels()) {
+ // If a metric labels were changed, we should remove it from the map, and place it back again
+ rms.push_back(metric->second);
+ family.second.erase(metric++);
+ dirty();
+ } else {
+ ++metric;
+ }
+ }
+ for (auto rm : rms) {
+ labels_type lb = rm->info().id.labels();
+ if (family.second.find(rm->info().id.labels()) != family.second.end()) {
+ /*
+ You can not have a two metrics with the same name and label, there is a problem with the configuration.
+ On startup we would have throw an exception and stop.
+ But during normal run, we don't want to crash the server just because a metric reconfiguration.
+ We cannot throw away the metric.
+ Instead we add it with an extra label, allowing the user to reconfigure.
+ */
+ seastar_logger.error("Metrics: After relabeling, registering metrics twice for metrics : {}", family.first);
+ auto id = get_unique_id();
+ lb["err"] = id;
+ conflicts.metrics_relabeled_due_to_collision++;
+ rm->info().id.labels()["err"] = id;
+ }
+
+ family.second[lb] = rm;
+ }
+ }
+ return make_ready_future<metric_relabeling_result>(conflicts);
+}
}

const bool metric_disabled = false;

+relabel_config::relabel_action relabel_config_action(const std::string& action) {
+ if (action == "skip_when_empty") {
+ return relabel_config::relabel_action::skip_when_empty;
+ }
+ if (action == "report_when_empty") {
+ return relabel_config::relabel_action::report_when_empty;
+ }
+ if (action == "keep") {
+ return relabel_config::relabel_action::keep;
+ }
+ if (action == "drop") {
+ return relabel_config::relabel_action::drop;
+ } if (action == "drop_label") {
+ return relabel_config::relabel_action::drop_label;
+ }
+ return relabel_config::relabel_action::replace;
+}

histogram& histogram::operator+=(const histogram& c) {
if (c.sample_count == 0) {
diff --git a/tests/unit/metrics_test.cc b/tests/unit/metrics_test.cc
--- a/tests/unit/metrics_test.cc
+++ b/tests/unit/metrics_test.cc
@@ -23,6 +23,7 @@
#include <seastar/core/metrics_registration.hh>
#include <seastar/core/metrics.hh>
#include <seastar/core/metrics_api.hh>
+#include <seastar/core/relabel_config.hh>
#include <seastar/core/reactor.hh>
#include <seastar/core/scheduling.hh>
#include <seastar/core/sleep.hh>
@@ -168,3 +169,151 @@ SEASTAR_THREAD_TEST_CASE(test_renaming_io_priority_classes) {
bool name2_found = label_vals.find(sstring(name2)) != label_vals.end();
BOOST_REQUIRE((name1_found && !name2_found) || (name2_found && !name1_found));
}
+
+int count_by_label(const std::string& label) {
+ seastar::foreign_ptr<seastar::metrics::impl::values_reference> values = seastar::metrics::impl::get_values();
+ int count = 0;
+ for (auto&& md : (*values->metadata)) {
+ for (auto&& mi : md.metrics) {
+ if (label == "" || mi.id.labels().find(label) != mi.id.labels().end()) {
+ count++;
+ }
+ }
+ }
+ return count;
+}
+
+int count_by_fun(std::function<bool(const seastar::metrics::impl::metric_info&)> f) {
+ seastar::foreign_ptr<seastar::metrics::impl::values_reference> values = seastar::metrics::impl::get_values();
+ int count = 0;
+ for (auto&& md : (*values->metadata)) {
+ for (auto&& mi : md.metrics) {
+ if (f(mi)) {
+ count++;
+ }
+ }
+ }
+ return count;
+}
+
+SEASTAR_THREAD_TEST_CASE(test_relabel_add_labels) {
+ using namespace seastar::metrics;
+ namespace sm = seastar::metrics;
+ sm::metric_groups app_metrics;
+ app_metrics.add_group("test", {
+ sm::make_gauge("gauge_1", sm::description("gague 1"), [] { return 0; }),
+ sm::make_counter("counter_1", sm::description("counter 1"), [] { return 1; })
+ });
+
+ std::vector<sm::relabel_config> rl(1);
+ rl[0].source_labels = {"__name__"};
+ rl[0].target_label = "level";
+ rl[0].replacement = "1";
+ rl[0].expr = "test_counter_.*";
+
+ sm::metric_relabeling_result success = sm::set_relabel_configs(rl).get();
+ BOOST_CHECK_EQUAL(success.metrics_relabeled_due_to_collision, 0);
+ BOOST_CHECK_EQUAL(count_by_label("level"), 1);
+ app_metrics.add_group("test", {
+ sm::make_counter("counter_2", sm::description("counter 2"), [] { return 2; })
+ });
+ BOOST_CHECK_EQUAL(count_by_label("level"), 2);
+ sm::set_relabel_configs({}).get();
+}
+
+SEASTAR_THREAD_TEST_CASE(test_relabel_drop_label_prevent_runtime_conflicts) {
+ using namespace seastar::metrics;
+ namespace sm = seastar::metrics;
+ sm::metric_groups app_metrics;
+ app_metrics.add_group("test2", {
+ sm::make_gauge("gauge_1", sm::description("gague 1"), { sm::label_instance("g", "1")}, [] { return 0; }),
+ sm::make_counter("counter_1", sm::description("counter 1"), [] { return 0; }),
+ sm::make_counter("counter_1", sm::description("counter 1"), { sm::label_instance("lev", "2")}, [] { return 0; })
+ });
+ BOOST_CHECK_EQUAL(count_by_label("lev"), 1);
+
+ std::vector<sm::relabel_config> rl(1);
+ rl[0].source_labels = {"lev"};
+ rl[0].expr = "2";
+ rl[0].target_label = "lev";
+ rl[0].action = sm::relabel_config::relabel_action::drop_label;
+ // Dropping the lev label would cause a conflict, but not crash the system
+ sm::metric_relabeling_result success = sm::set_relabel_configs(rl).get();
+ BOOST_CHECK_EQUAL(success.metrics_relabeled_due_to_collision, 1);
+ BOOST_CHECK_EQUAL(count_by_label("lev"), 0);
+ BOOST_CHECK_EQUAL(count_by_label("err"), 1);
+
+ //reseting all the labels to their original state
+ success = sm::set_relabel_configs({}).get();
+ BOOST_CHECK_EQUAL(success.metrics_relabeled_due_to_collision, 0);
+ BOOST_CHECK_EQUAL(count_by_label("lev"), 1);
+ BOOST_CHECK_EQUAL(count_by_label("err"), 0);
+ sm::set_relabel_configs({}).get();
+}
+
+SEASTAR_THREAD_TEST_CASE(test_relabel_enable_disable_skip_when_empty) {
+ using namespace seastar::metrics;
+ namespace sm = seastar::metrics;
+ sm::metric_groups app_metrics;
+ app_metrics.add_group("test3", {
+ sm::make_gauge("gauge_1", sm::description("gague 1"), { sm::label_instance("lev3", "3")}, [] { return 0; }),
+ sm::make_counter("counter_1", sm::description("counter 1"), { sm::label_instance("lev3", "3")}, [] { return 0; }),
+ sm::make_counter("counter_2", sm::description("counter 2"), { sm::label_instance("lev3", "3")}, [] { return 0; })
+ });
+ std::vector<sm::relabel_config> rl(2);
+ rl[0].source_labels = {"__name__"};
+ rl[0].action = sm::relabel_config::relabel_action::drop;
+
+ rl[1].source_labels = {"lev3"};
+ rl[1].expr = "3";
+ rl[1].action = sm::relabel_config::relabel_action::keep;
+ // We just disable all metrics besides those mark as lev3
+ sm::metric_relabeling_result success = sm::set_relabel_configs(rl).get();
+ BOOST_CHECK_EQUAL(success.metrics_relabeled_due_to_collision, 0);
+ BOOST_CHECK_EQUAL(count_by_label(""), 3);
+ BOOST_CHECK_EQUAL(count_by_fun([](const seastar::metrics::impl::metric_info& mi) {
+ return mi.should_skip_when_empty == sm::skip_when_empty::yes;
+ }), 0);
+
+ std::vector<sm::relabel_config> rl2(3);
+ rl2[0].source_labels = {"__name__"};
+ rl2[0].action = sm::relabel_config::relabel_action::drop;
+
+ rl2[1].source_labels = {"lev3"};
+ rl2[1].expr = "3";
+ rl2[1].action = sm::relabel_config::relabel_action::keep;
+
+ rl2[2].source_labels = {"__name__"};
+ rl2[2].expr = "test3.*";
+ rl2[2].action = sm::relabel_config::relabel_action::skip_when_empty;
+
+ success = sm::set_relabel_configs(rl2).get();
+ BOOST_CHECK_EQUAL(success.metrics_relabeled_due_to_collision, 0);
+ BOOST_CHECK_EQUAL(count_by_label(""), 3);
+ BOOST_CHECK_EQUAL(count_by_fun([](const seastar::metrics::impl::metric_info& mi) {
+ return mi.should_skip_when_empty == sm::skip_when_empty::yes;
+ }), 3);
+ // clear the configuration
+ success = sm::set_relabel_configs({}).get();
+ app_metrics.add_group("test3", {
+ sm::make_counter("counter_3", sm::description("counter 2"), { sm::label_instance("lev3", "3")}, [] { return 0; })(sm::skip_when_empty::yes)
+ });
+ std::vector<sm::relabel_config> rl3(3);
+ rl3[0].source_labels = {"__name__"};
+ rl3[0].action = sm::relabel_config::relabel_action::drop;
+
+ rl3[1].source_labels = {"lev3"};
+ rl3[1].expr = "3";
+ rl3[1].action = sm::relabel_config::relabel_action::keep;
+
+ rl3[2].source_labels = {"__name__"};
+ rl3[2].expr = "test3.*";
+ rl3[2].action = sm::relabel_config::relabel_action::report_when_empty;
+
+ success = sm::set_relabel_configs(rl3).get();
+ BOOST_CHECK_EQUAL(success.metrics_relabeled_due_to_collision, 0);
+ BOOST_CHECK_EQUAL(count_by_fun([](const seastar::metrics::impl::metric_info& mi) {
+ return mi.should_skip_when_empty == sm::skip_when_empty::yes;
+ }), 0);
+ sm::set_relabel_configs({}).get();
+}
Reply all
Reply to author
Forward
0 new messages