Skip to content

Commit

Permalink
filter by label value
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos committed Aug 12, 2024
1 parent a2d0961 commit e636a19
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 81 deletions.
1 change: 1 addition & 0 deletions include/ylt/metric/metric.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ enum class MetricType {
struct metric_filter_options {
std::optional<std::regex> name_regex{};
std::optional<std::regex> label_regex{};
std::optional<std::regex> label_value_regex{};
bool is_white = true;
};

Expand Down
139 changes: 74 additions & 65 deletions include/ylt/metric/metric_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,63 +69,74 @@ class manager_helper {
}
#endif

static std::vector<std::shared_ptr<metric_t>> filter_metrics_by_label_value(
auto& metrics, const std::regex& label_regex, bool is_white) {
static std::vector<std::shared_ptr<metric_t>> filter_metrics_by_name(
auto& metrics, const std::regex& name_regex) {
std::vector<std::shared_ptr<metric_t>> filtered_metrics;
for (auto& m : metrics) {
if (std::regex_match(m->str_name(), name_regex)) {
filtered_metrics.push_back(m);
}
}
return filtered_metrics;
}

static std::vector<std::shared_ptr<metric_t>> filter_metrics_by_label_name(
auto& metrics, const std::regex& label_name_regex) {
std::vector<std::shared_ptr<metric_t>> filtered_metrics;
std::vector<size_t> indexs;
size_t index = 0;
for (auto& m : metrics) {
if (m->has_label_value(label_regex)) {
if (is_white) {
const auto& labels_name = m->labels_name();
for (auto& label_name : labels_name) {
if (std::regex_match(label_name, label_name_regex)) {
filtered_metrics.push_back(m);
}
else {
indexs.push_back(index);
}
}

index++;
}
return filtered_metrics;
}

if (!is_white) {
for (size_t i : indexs) {
metrics.erase(std::next(metrics.begin(), i));
static std::vector<std::shared_ptr<metric_t>> filter_metrics_by_label_value(
auto& metrics, const std::regex& label_value_regex) {
std::vector<std::shared_ptr<metric_t>> filtered_metrics;
for (auto& m : metrics) {
if (m->has_label_value(label_value_regex)) {
filtered_metrics.push_back(m);
}
return metrics;
}

return filtered_metrics;
}

static std::vector<std::shared_ptr<metric_t>> filter_metrics(
auto& metrics, const metric_filter_options& options) {
if (!options.name_regex && !options.label_regex) {
if (!(options.name_regex || options.label_regex ||
options.label_value_regex)) {
return metrics;
}

std::vector<std::shared_ptr<metric_t>> filtered_metrics;
for (auto& m : metrics) {
if (options.name_regex &&
!options.label_regex) { // only check metric name
if (std::regex_match(std::string(m->name()), *options.name_regex)) {
filtered_metrics.push_back(m);
}
std::vector<std::shared_ptr<metric_t>> filtered_metrics = metrics;
if (options.name_regex) {
filtered_metrics = filter_metrics_by_name(metrics, *options.name_regex);
if (filtered_metrics.empty()) {
return {};
}
else if (options.label_regex &&
!options.name_regex) { // only check label name
filter_by_label_name(filtered_metrics, m, options);
}

if (options.label_regex) {
filtered_metrics =
filter_metrics_by_label_name(filtered_metrics, *options.label_regex);
if (filtered_metrics.empty()) {
return {};
}
else {
if (std::regex_match(
std::string(m->name()),
*options.name_regex)) { // check label name and label value
filter_by_label_name(filtered_metrics, m, options);
}
}

if (options.label_value_regex) {
filtered_metrics = filter_metrics_by_label_value(
filtered_metrics, *options.label_value_regex);
if (filtered_metrics.empty()) {
return {};
}
}

if (!options.is_white) {
auto it = metrics.begin();
for (auto& m : filtered_metrics) {
std::erase_if(metrics, [&](auto t) {
return t == m;
Expand Down Expand Up @@ -239,19 +250,18 @@ class static_metric_manager {
return metrics;
}

std::vector<std::shared_ptr<metric_t>> filter_metrics_by_label_value(
const std::regex& label_regex, bool is_white = true) {
auto metrics = collect();
return manager_helper::filter_metrics_by_label_value(metrics, label_regex,
is_white);
}

std::vector<std::shared_ptr<metric_t>> filter_metrics_static(
const metric_filter_options& options) {
auto metrics = collect();
return manager_helper::filter_metrics(metrics, options);
}

std::vector<std::shared_ptr<metric_t>> filter_metrics_by_label_value(
const std::regex& label_regex) {
auto metrics = collect();
return manager_helper::filter_metrics_by_label_value(metrics, label_regex);
}

private:
static_metric_manager() = default;

Expand Down Expand Up @@ -498,34 +508,40 @@ class dynamic_metric_manager {
}

std::vector<std::shared_ptr<metric_t>> filter_metrics_by_label_value(
const std::regex& label_regex, bool is_white = true) {
const std::regex& label_regex) {
auto metrics = collect();
return manager_helper::filter_metrics_by_label_value(metrics, label_regex,
is_white);
return manager_helper::filter_metrics_by_label_value(metrics, label_regex);
}

private:
void clean_label_expired() {
executor_ = coro_io::create_io_context_pool(1);
timer_ = std::make_shared<coro_io::period_timer>(executor_->get_executor());
check_label_expired().via(executor_->get_executor()).start([](auto&&) {
});
check_label_expired(timer_)
.via(executor_->get_executor())
.start([](auto&&) {
});
}

async_simple::coro::Lazy<void> check_label_expired() {
auto timer = timer_;
timer_->expires_after(ylt_label_check_expire_duration);
bool r = co_await timer_->async_await();
if (!r) {
co_return;
}
async_simple::coro::Lazy<void> check_label_expired(
std::weak_ptr<coro_io::period_timer> weak) {
while (true) {
auto timer = weak.lock();
if (timer == nullptr) {
co_return;
}

std::unique_lock lock(mtx_);
for (auto& [_, m] : metric_map_) {
m->clean_expired_label();
timer->expires_after(ylt_label_check_expire_duration);
bool r = co_await timer->async_await();
if (!r) {
co_return;
}

std::unique_lock lock(mtx_);
for (auto& [_, m] : metric_map_) {
m->clean_expired_label();
}
}
lock.unlock();
co_await check_label_expired();
}

dynamic_metric_manager() {
Expand Down Expand Up @@ -611,13 +627,6 @@ struct metric_collector_t {
return manager_helper::filter_metrics(vec, options);
}

static std::vector<std::shared_ptr<metric_t>> filter_metrics_by_label_value(
const std::regex& label_regex, bool is_white = true) {
auto vec = get_all_metrics();
return manager_helper::filter_metrics_by_label_value(vec, label_regex,
is_white);
}

private:
template <typename T>
static void append_vector(std::vector<std::shared_ptr<metric_t>>& vec) {
Expand Down
39 changes: 23 additions & 16 deletions src/metric/tests/test_metric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,6 @@ struct metrc_tag {};

struct test_tag {};

TEST_CASE("test metric manager clean expired label") {
set_label_max_age(std::chrono::seconds(1), std::chrono::seconds(1));
auto& inst = dynamic_metric_manager<test_tag>::instance();
auto [ec, c] = inst.create_metric_dynamic<dynamic_counter_1t>(
std::string("some_counter"), "", std::array<std::string, 1>{"url"});
c->inc({"/"});
c->inc({"/test"});
std::this_thread::sleep_for(std::chrono::seconds(2));
c->inc({"/index"});
size_t count = c->label_value_count();
CHECK(count == 1);
}

TEST_CASE("test metric manager") {
auto c = std::make_shared<counter_t>("test1", "");
auto g = std::make_shared<gauge_t>("test2", "");
Expand Down Expand Up @@ -144,7 +131,7 @@ TEST_CASE("test metric manager") {
CHECK(inst_d.metric_count() == 0);
inst_d.register_metric(dc);

inst_d.create_metric_dynamic<dynamic_counter_t>(
auto pair2 = inst_d.create_metric_dynamic<dynamic_counter_t>(
"test4", "", std::array<std::string, 2>{"method", "code"});

metric_filter_options options;
Expand All @@ -155,8 +142,14 @@ TEST_CASE("test metric manager") {
auto v6 = inst_d.filter_metrics_dynamic(options);
CHECK(v6.size() == 1);

auto v7 = inst_d.filter_metrics_by_label_value(std::regex("200"));
CHECK(v7.size() == 1);
options.label_value_regex = "200";

auto v7 = inst_d.filter_metrics_dynamic(options);
CHECK(v7.size() == 0);

pair2.second->inc({"200"});
auto v8 = inst_d.filter_metrics_dynamic(options);
CHECK(v8.size() == 1);
}

TEST_CASE("test dynamic counter") {
Expand Down Expand Up @@ -1517,6 +1510,20 @@ TEST_CASE("testFilterMetricsDynamicWithMultiLabel") {
}
}

TEST_CASE("test metric manager clean expired label") {
set_label_max_age(std::chrono::seconds(1), std::chrono::seconds(1));
auto& inst = dynamic_metric_manager<test_tag>::instance();
auto [ec, c] = inst.create_metric_dynamic<dynamic_counter_1t>(
std::string("some_counter"), "", std::array<std::string, 1>{"url"});
c->inc({"/"});
c->inc({"/test"});
CHECK(c->label_value_count() == 2);
std::this_thread::sleep_for(std::chrono::seconds(2));
c->inc({"/index"});
size_t count = c->label_value_count();
CHECK(count == 1);
}

DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007)
int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); }
DOCTEST_MSVC_SUPPRESS_WARNING_POP

0 comments on commit e636a19

Please sign in to comment.