Skip to content

Commit

Permalink
Merge pull request #160 from redpanda-data/stephan/downstream-metrics…
Browse files Browse the repository at this point in the history
…-improvements

Downstream metrics improvements
  • Loading branch information
StephanDollberg authored Dec 24, 2024
2 parents f194d34 + 7b10c61 commit 886d078
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 105 deletions.
4 changes: 2 additions & 2 deletions apps/io_tester/io_tester.cc
Original file line number Diff line number Diff line change
Expand Up @@ -631,8 +631,8 @@ class io_class_data : public class_data {
const auto& mf = values.find(m_name);
assert(mf != values.end());
for (auto&& mi : mf->second) {
auto&& cname = mi.first.find("class");
if (cname != mi.first.end() && cname->second == name()) {
auto&& cname = mi.first.labels().find("class");
if (cname != mi.first.labels().end() && cname->second == name()) {
out << YAML::Key << m_name << YAML::Value << mi.second->get_function()().d();
}
}
Expand Down
154 changes: 124 additions & 30 deletions include/seastar/core/metrics_api.hh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include <seastar/core/metrics.hh>
#include <seastar/util/modules.hh>
#include <seastar/core/shared_ptr.hh>
#include <seastar/core/sharded.hh>
#ifndef SEASTAR_MODULE
#include <boost/functional/hash.hpp>
Expand All @@ -45,6 +46,8 @@ using labels_type = std::map<sstring, sstring>;

int default_handle();

using internalized_labels_ref = lw_shared_ptr<const labels_type>;

}
}
}
Expand Down Expand Up @@ -109,7 +112,7 @@ class metric_id {
public:
metric_id() = default;
metric_id(group_name_type group, metric_name_type name,
labels_type labels = {})
internalized_labels_ref labels)
: _group(std::move(group)), _name(
std::move(name)), _labels(labels) {
}
Expand All @@ -126,17 +129,20 @@ public:
_group = name;
}
const instance_id_type & instance_id() const {
return _labels.at(shard_label.name());
return _labels->at(shard_label.name());
}
const metric_name_type & name() const {
return _name;
}
const labels_type& labels() const {
return _labels;
return *_labels;
}
labels_type& labels() {
internalized_labels_ref internalized_labels() const {
return _labels;
}
void update_labels(internalized_labels_ref labels) {
_labels = labels;
}
sstring full_name() const;

bool operator<(const metric_id&) const;
Expand All @@ -147,7 +153,7 @@ private:
}
group_name_type _group;
metric_name_type _name;
labels_type _labels;
internalized_labels_ref _labels;
};
}
}
Expand Down Expand Up @@ -194,38 +200,54 @@ struct metric_family_info {
*/
struct metric_info {
metric_id id;
labels_type original_labels;
internalized_labels_ref original_labels;
bool enabled;
skip_when_empty should_skip_when_empty;
};

class internalized_holder {
internalized_labels_ref _labels;
public:
explicit internalized_holder(labels_type labels) : _labels(make_lw_shared<labels_type>(std::move(labels))) {
}

using metrics_registration = std::vector<metric_id>;
explicit internalized_holder(internalized_labels_ref labels) : _labels(std::move(labels)) {
}

class metric_groups_impl : public metric_groups_def {
int _handle;
metrics_registration _registration;
public:
explicit metric_groups_impl(int handle = default_handle());
~metric_groups_impl();
metric_groups_impl(const metric_groups_impl&) = delete;
metric_groups_impl(metric_groups_impl&&) = default;
metric_groups_impl& add_metric(group_name_type name, const metric_definition& md);
metric_groups_impl& add_group(group_name_type name, const std::initializer_list<metric_definition>& l);
metric_groups_impl& add_group(group_name_type name, const std::vector<metric_definition>& l);
int get_handle() const;
internalized_labels_ref labels_ref() const {
return _labels;
}

const labels_type& labels() const {
return *_labels;
}

size_t has_users() const {
// Getting the count wrong isn't a correctness issue but will just make internalization worse
return _labels.use_count() > 1;
}
};

inline bool operator<(const internalized_holder& lhs, const labels_type& rhs) {
return lhs.labels() < rhs;
}
inline bool operator<(const labels_type& lhs, const internalized_holder& rhs) {
return lhs < rhs.labels();
}
inline bool operator<(const internalized_holder& lhs, const internalized_holder& rhs) {
return lhs.labels() < rhs.labels();
}


class impl;
using metric_implementations = std::unordered_map<int, ::seastar::shared_ptr<impl>>;
metric_implementations& get_metric_implementations();

class registered_metric final {
metric_info _info;
metric_function _f;
shared_ptr<impl> _impl;
public:
registered_metric(metric_id id, metric_function f, bool enabled=true, skip_when_empty skip=skip_when_empty::no, int handle=default_handle());
registered_metric(metric_id id, metric_function f, bool enabled=true, skip_when_empty skip=skip_when_empty::no);
metric_value operator()() const {
return _f();
}
Expand Down Expand Up @@ -261,7 +283,23 @@ public:
};

using register_ref = shared_ptr<registered_metric>;
using metric_instances = std::map<labels_type, register_ref>;
using metric_instances = std::map<internalized_holder, register_ref, std::less<>>;
using metrics_registration = std::vector<register_ref>;

class metric_groups_impl : public metric_groups_def {
int _handle;
metrics_registration _registration;
shared_ptr<impl> _impl; // keep impl alive while metrics are registered
public:
metric_groups_impl(int handle = default_handle());
~metric_groups_impl();
metric_groups_impl(const metric_groups_impl&) = delete;
metric_groups_impl(metric_groups_impl&&) = default;
metric_groups_impl& add_metric(group_name_type name, const metric_definition& md);
metric_groups_impl& add_group(group_name_type name, const std::initializer_list<metric_definition>& l);
metric_groups_impl& add_group(group_name_type name, const std::vector<metric_definition>& l);
int get_handle() const;
};

class metric_family {
metric_instances _instances;
Expand All @@ -281,12 +319,12 @@ public:
metric_family(metric_instances&& instances) : _instances(std::move(instances)) {
}

register_ref& operator[](const labels_type& l) {
return _instances[l];
register_ref& operator[](const internalized_labels_ref& l) {
return _instances[internalized_holder(l)];
}

const register_ref& at(const labels_type& l) const {
return _instances.at(l);
const register_ref& at(const internalized_labels_ref& l) const {
return _instances.at(internalized_holder(l));
}

metric_family_info& info() {
Expand Down Expand Up @@ -337,7 +375,50 @@ public:

using value_map = std::map<sstring, metric_family>;

using metric_metadata_fifo = std::deque<metric_info>;
/*!
* \brief Subset of the per series metadata that is shared via get_values to other shards.
*
* Allows omitting metadata that is already stored elsewhere or not needed by
* the metrics scrap handlers.
*
* Not copyable to allow for safely sharing internalized data.
*/
class metric_series_metadata {
// prom backend only needs the label from here but scollectd needs group and
// metric name separately. metric_family_info only stores the merged and
// filtered name so we have to duplicate it here.
metric_id _id;
skip_when_empty _should_skip_when_empty;
public:
metric_series_metadata() = default;
metric_series_metadata(metric_id id, skip_when_empty should_skip_when_empty)
: _id(std::move(id)), _should_skip_when_empty(should_skip_when_empty) {
}

metric_series_metadata(const metric_series_metadata&) = delete;
metric_series_metadata& operator=(const metric_series_metadata&) = delete;

metric_series_metadata(metric_series_metadata&&) noexcept = default;
metric_series_metadata& operator=(metric_series_metadata&&) noexcept = default;

const labels_type& labels() const {
return _id.labels();
}

skip_when_empty should_skip_when_empty() const {
return _should_skip_when_empty;
}

group_name_type group_name() const {
return _id.group_name();
}

group_name_type name() const {
return _id.name();
}
};

using metric_metadata_fifo = std::deque<metric_series_metadata>;

/*!
* \brief holds a metric family metadata
Expand All @@ -354,8 +435,16 @@ using metric_metadata_fifo = std::deque<metric_info>;
struct metric_family_metadata {
metric_family_info mf;
metric_metadata_fifo metrics;

metric_family_metadata() = default;
metric_family_metadata(metric_family_metadata &&) = default;
metric_family_metadata &operator=(metric_family_metadata &&) = default;
metric_family_metadata(metric_family_info mf, metric_metadata_fifo metrics)
: mf(std::move(mf)), metrics(std::move(metrics)) {}
};

static_assert(std::is_nothrow_move_assignable_v<metric_family_metadata>);

using value_vector = std::deque<metric_value>;
using metric_metadata = std::vector<metric_family_metadata>;
using metric_values = std::deque<value_vector>;
Expand All @@ -369,6 +458,8 @@ struct config {
sstring hostname;
};

using internalized_set = std::set<internalized_holder, std::less<>>;

class impl {
value_map _value_map;
config _config;
Expand All @@ -379,6 +470,7 @@ class impl {
std::vector<relabel_config> _relabel_configs;
std::vector<metric_family_config> _metric_family_configs;
std::unordered_multimap<seastar::sstring, int> _metric_families_to_replicate;
internalized_set _internalized_labels;
public:
value_map& get_value_map() {
return _value_map;
Expand All @@ -388,8 +480,9 @@ public:
return _value_map;
}

void 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, int handle = default_handle());
register_ref 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);
void update_aggregate_labels(const metric_id& id, const std::vector<label>& aggregate_labels);
internalized_labels_ref internalize_labels(labels_type labels);
void remove_registration(const metric_id& id);
future<> stop() {
return make_ready_future<>();
Expand Down Expand Up @@ -451,14 +544,15 @@ private:
void replicate_metric_if_required(const shared_ptr<registered_metric>& metric) const;
void replicate_metric(const shared_ptr<registered_metric>& metric,
const metric_family& family,
const shared_ptr<impl>& destination,
int destination_handle) const;
const shared_ptr<impl>& destination) const;

void remove_metric_replica_family(const seastar::sstring& name,
int destination_handle) const;
void remove_metric_replica(const metric_id& id,
const shared_ptr<impl>& destination) const;
void remove_metric_replica_if_required(const metric_id& id) const;
void gc_internalized_labels();
bool apply_relabeling(const relabel_config& rc, metric_info& info);
};

const value_map& get_value_map(int handle = default_handle());
Expand Down
Loading

0 comments on commit 886d078

Please sign in to comment.