Commit f20b13b0 authored by Dominik Charousset's avatar Dominik Charousset

Revise the metric family API

parent 6b1bd132
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
...@@ -29,7 +30,7 @@ namespace caf::telemetry::collector { ...@@ -29,7 +30,7 @@ namespace caf::telemetry::collector {
/// Collects system metrics and exports them to the text-based Prometheus /// Collects system metrics and exports them to the text-based Prometheus
/// format. For a documentation of the format, see: https://git.io/fjgDD. /// format. For a documentation of the format, see: https://git.io/fjgDD.
class prometheus { class CAF_CORE_EXPORT prometheus {
public: public:
// -- member types ----------------------------------------------------------- // -- member types -----------------------------------------------------------
......
...@@ -23,12 +23,16 @@ ...@@ -23,12 +23,16 @@
#include <atomic> #include <atomic>
#include <cstdint> #include <cstdint>
#include "caf/telemetry/metric_type.hpp"
namespace caf::telemetry { namespace caf::telemetry {
/// A metric that represents a single integer value that can arbitrarily go up /// A metric that represents a single integer value that can arbitrarily go up
/// and down. /// and down.
class CAF_CORE_EXPORT int_gauge { class CAF_CORE_EXPORT int_gauge {
public: public:
static constexpr metric_type runtime_type = metric_type::int_gauge;
int_gauge() noexcept : value_(0) { int_gauge() noexcept : value_(0) {
// nop // nop
} }
...@@ -38,22 +42,22 @@ public: ...@@ -38,22 +42,22 @@ public:
} }
/// Increments the gauge by 1. /// Increments the gauge by 1.
void increment() noexcept { void inc() noexcept {
++value_; ++value_;
} }
/// Increments the gauge by `amount`. /// Increments the gauge by `amount`.
void increment(int64_t amount) noexcept { void inc(int64_t amount) noexcept {
value_.fetch_add(amount); value_.fetch_add(amount);
} }
/// Decrements the gauge by 1. /// Decrements the gauge by 1.
void decrement() noexcept { void dec() noexcept {
--value_; --value_;
} }
/// Decrements the gauge by `amount`. /// Decrements the gauge by `amount`.
void decrement(int64_t amount) noexcept { void dec(int64_t amount) noexcept {
value_.fetch_sub(amount); value_.fetch_sub(amount);
} }
......
...@@ -77,6 +77,8 @@ public: ...@@ -77,6 +77,8 @@ public:
return is_sum_; return is_sum_;
} }
virtual metric_type type() const noexcept = 0;
private: private:
std::string prefix_; std::string prefix_;
std::string name_; std::string name_;
......
...@@ -19,9 +19,12 @@ ...@@ -19,9 +19,12 @@
#pragma once #pragma once
#include <algorithm> #include <algorithm>
#include <initializer_list>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include "caf/span.hpp"
#include "caf/string_view.hpp"
#include "caf/telemetry/label.hpp" #include "caf/telemetry/label.hpp"
#include "caf/telemetry/label_view.hpp" #include "caf/telemetry/label_view.hpp"
#include "caf/telemetry/metric.hpp" #include "caf/telemetry/metric.hpp"
...@@ -33,27 +36,34 @@ namespace caf::telemetry { ...@@ -33,27 +36,34 @@ namespace caf::telemetry {
template <class Type> template <class Type>
class metric_family_impl : public metric_family { class metric_family_impl : public metric_family {
public: public:
using metric_type = metric_impl<Type>; using impl_type = metric_impl<Type>;
using metric_family::metric_family; using metric_family::metric_family;
Type* get_or_add(const std::vector<label_view>& labels) { metric_type type() const noexcept override {
auto has_label_values = [&labels](const auto& metric_ptr) { return Type::runtime_type;
}
Type* get_or_add(span<const label_view> labels) {
auto has_label_values = [labels](const auto& metric_ptr) {
const auto& metric_labels = metric_ptr->labels(); const auto& metric_labels = metric_ptr->labels();
for (size_t index = 0; index < labels.size(); ++index) return std::is_permutation(metric_labels.begin(), metric_labels.end(),
if (labels[index].value() != metric_labels[index].value()) labels.begin(), labels.end());
return false;
return true;
}; };
std::unique_lock<std::mutex> guard{mx_}; std::unique_lock<std::mutex> guard{mx_};
auto m = std::find_if(metrics_.begin(), metrics_.end(), has_label_values); auto m = std::find_if(metrics_.begin(), metrics_.end(), has_label_values);
if (m == metrics_.end()) { if (m == metrics_.end()) {
std::vector<label> cpy{labels.begin(), labels.end()}; std::vector<label> cpy{labels.begin(), labels.end()};
m = metrics_.emplace(m, std::make_unique<metric_type>(std::move(cpy))); std::sort(cpy.begin(), cpy.end());
m = metrics_.emplace(m, std::make_unique<impl_type>(std::move(cpy)));
} }
return std::addressof(m->get()->impl()); return std::addressof(m->get()->impl());
} }
Type* get_or_add(std::initializer_list<label_view> labels) {
return get_or_add(span<const label_view>{labels.begin(), labels.size()});
}
template <class Collector> template <class Collector>
void collect(Collector& collector) const { void collect(Collector& collector) const {
std::unique_lock<std::mutex> guard{mx_}; std::unique_lock<std::mutex> guard{mx_};
...@@ -63,7 +73,7 @@ public: ...@@ -63,7 +73,7 @@ public:
private: private:
mutable std::mutex mx_; mutable std::mutex mx_;
std::vector<std::unique_ptr<metric_type>> metrics_; std::vector<std::unique_ptr<impl_type>> metrics_;
}; };
} // namespace caf::telemetry } // namespace caf::telemetry
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#pragma once #pragma once
#include <initializer_list>
#include <map> #include <map>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
...@@ -42,26 +43,8 @@ public: ...@@ -42,26 +43,8 @@ public:
~metric_registry(); ~metric_registry();
/// Adds a new metric family to the registry. /// Returns a metric family. Creates the family lazily if necessary, but fails
/// @param type The kind of the metric, e.g. gauge or count. /// if the full name already belongs to a different family.
/// @param prefix The prefix (namespace) this family belongs to. Usually the
/// application or protocol name, e.g., `http`. The prefix `caf`
/// as well as prefixes starting with an underscore are
/// reserved.
/// @param name The human-readable name of the metric, e.g., `requests`.
/// @param label_names Names for all label dimensions of the metric.
/// @param helptext Short explanation of the metric.
/// @param unit Unit of measurement. Please use base units such as `bytes` or
/// `seconds` (prefer lowercase). The pseudo-unit `1` identifies
/// dimensionless counts.
/// @param is_sum Setting this to `true` indicates that this metric adds
/// something up to a total, where only the total value is of
/// interest. For example, the total number of HTTP requests.
void add_family(metric_type type, std::string prefix, std::string name,
std::vector<std::string> label_names, std::string helptext,
std::string unit = "1", bool is_sum = false);
/// Adds a new metric family to the registry.
/// @param prefix The prefix (namespace) this family belongs to. Usually the /// @param prefix The prefix (namespace) this family belongs to. Usually the
/// application or protocol name, e.g., `http`. The prefix `caf` /// application or protocol name, e.g., `http`. The prefix `caf`
/// as well as prefixes starting with an underscore are /// as well as prefixes starting with an underscore are
...@@ -76,25 +59,40 @@ public: ...@@ -76,25 +59,40 @@ public:
/// something up to a total, where only the total value is of /// something up to a total, where only the total value is of
/// interest. For example, the total number of HTTP requests. /// interest. For example, the total number of HTTP requests.
template <class Type> template <class Type>
metric_family_impl<Type>* metric_family_impl<Type>* family(string_view prefix, string_view name,
add_family(std::string prefix, std::string name, span<const string_view> label_names,
std::vector<std::string> label_names, std::string helptext, string_view helptext, string_view unit = "1",
std::string unit = "1", bool is_sum = false) { bool is_sum = false) {
using family_type = metric_family_impl<Type>; using family_type = metric_family_impl<Type>;
std::sort(label_names.begin(), label_names.end());
auto ptr = std::make_unique<family_type>(std::move(prefix), std::move(name),
std::move(label_names),
std::move(helptext),
std::move(unit), is_sum);
std::unique_lock<std::mutex> guard{families_mx_}; std::unique_lock<std::mutex> guard{families_mx_};
assert_unregistered(ptr->prefix(), ptr->name()); if (auto ptr = fetch(prefix, name)) {
assert_properties(ptr, Type::runtime_type, label_names, unit, is_sum);
return static_cast<family_type*>(ptr);
}
auto ptr = std::make_unique<family_type>(to_string(prefix), to_string(name),
to_sorted_vec(label_names),
to_string(helptext),
to_string(unit), is_sum);
auto& families = container_by_type<Type>(); auto& families = container_by_type<Type>();
families.emplace_back(std::move(ptr)); families.emplace_back(std::move(ptr));
return families.back().get(); return families.back().get();
} }
/// Adds a new metric singleton, i.e., a family without label dimensions and /// @copydoc family
/// thus exactly one metric instance. template <class Type>
metric_family_impl<Type>*
family(string_view prefix, string_view name,
std::initializer_list<string_view> label_names, string_view helptext,
string_view unit = "1", bool is_sum = false) {
return family<Type>(prefix, name,
span<const string_view>{label_names.begin(),
label_names.size()},
helptext, unit, is_sum);
}
/// Returns a metric singleton, i.e., the single instance of a family without
/// label dimensions. Creates all objects lazily if necessary, but fails if
/// the full name already belongs to a different family.
/// @param prefix The prefix (namespace) this family belongs to. Usually the /// @param prefix The prefix (namespace) this family belongs to. Usually the
/// application or protocol name, e.g., `http`. The prefix `caf` /// application or protocol name, e.g., `http`. The prefix `caf`
/// as well as prefixes starting with an underscore are /// as well as prefixes starting with an underscore are
...@@ -108,17 +106,12 @@ public: ...@@ -108,17 +106,12 @@ public:
/// something up to a total, where only the total value is of /// something up to a total, where only the total value is of
/// interest. For example, the total number of HTTP requests. /// interest. For example, the total number of HTTP requests.
template <class Type> template <class Type>
Type* add_singleton(std::string prefix, std::string name, Type* singleton(string_view prefix, string_view name, string_view helptext,
std::string helptext, std::string unit = "1", string_view unit = "1", bool is_sum = false) {
bool is_sum = false) { auto fptr = family<Type>(prefix, name, {}, helptext, unit, is_sum);
auto fptr = add_family<Type>(std::move(prefix), std::move(name), {},
std::move(helptext), std::move(unit), is_sum);
return fptr->get_or_add({}); return fptr->get_or_add({});
} }
telemetry::int_gauge* int_gauge(string_view prefix, string_view name,
std::vector<label_view> labels);
template <class Collector> template <class Collector>
void collect(Collector& collector) const { void collect(Collector& collector) const {
std::unique_lock<std::mutex> guard{families_mx_}; std::unique_lock<std::mutex> guard{families_mx_};
...@@ -128,7 +121,22 @@ public: ...@@ -128,7 +121,22 @@ public:
private: private:
/// @pre `families_mx_` is locked. /// @pre `families_mx_` is locked.
void assert_unregistered(const std::string& prefix, const std::string& name); metric_family* fetch(const string_view& prefix, const string_view& name);
static std::vector<std::string> to_sorted_vec(span<const string_view> xs) {
std::vector<std::string> result;
if (!xs.empty()) {
result.reserve(xs.size());
for (auto x : xs)
result.emplace_back(to_string(x));
std::sort(result.begin(), result.end());
}
return result;
}
void assert_properties(metric_family* ptr, metric_type type,
span<const string_view> label_names, string_view unit,
bool is_sum);
template <class Type> template <class Type>
metric_family_container<Type>& container_by_type(); metric_family_container<Type>& container_by_type();
......
...@@ -49,7 +49,7 @@ actor_registry::~actor_registry() { ...@@ -49,7 +49,7 @@ actor_registry::~actor_registry() {
} }
actor_registry::actor_registry(actor_system& sys) : system_(sys) { actor_registry::actor_registry(actor_system& sys) : system_(sys) {
running_ = sys.telemetry().add_singleton<telemetry::int_gauge>( running_ = sys.telemetry().singleton<telemetry::int_gauge>(
"caf", "running_actors", "Number of currently running actors."); "caf", "running_actors", "Number of currently running actors.");
} }
......
...@@ -35,74 +35,35 @@ metric_registry::~metric_registry() { ...@@ -35,74 +35,35 @@ metric_registry::~metric_registry() {
// nop // nop
} }
telemetry::int_gauge* metric_family* metric_registry::fetch(const string_view& prefix,
metric_registry::int_gauge(string_view prefix, string_view name, const string_view& name) {
std::vector<label_view> labels) { auto matches = [&](const auto& ptr) {
// Make sure labels are sorted by name. return ptr->prefix() == prefix && ptr->name() == name;
auto cmp = [](const label_view& x, const label_view& y) {
return x.name() < y.name();
};
std::sort(labels.begin(), labels.end(), cmp);
// Fetch the family.
auto matches = [&](const auto& family) {
auto lbl_cmp = [](const label_view& lbl, string_view name) {
return lbl.name() == name;
};
return family->prefix() == prefix && family->name() == name
&& std::equal(labels.begin(), labels.end(),
family->label_names().begin(),
family->label_names().end(), lbl_cmp);
}; };
using family_type = metric_family_impl<telemetry::int_gauge>; if (auto i = std::find_if(int_gauges_.begin(), int_gauges_.end(), matches);
family_type* fptr; i != int_gauges_.end())
{ return i->get();
std::unique_lock<std::mutex> guard{families_mx_}; return nullptr;
auto i = std::find_if(int_gauges_.begin(), int_gauges_.end(), matches);
if (i == int_gauges_.end()) {
std::string prefix_str{prefix.begin(), prefix.end()};
std::string name_str{name.begin(), name.end()};
assert_unregistered(prefix_str, name_str);
std::vector<std::string> label_names;
label_names.reserve(labels.size());
for (auto& lbl : labels) {
auto lbl_name = lbl.name();
label_names.emplace_back(std::string{lbl_name.begin(), lbl_name.end()});
}
auto ptr = std::make_unique<family_type>(std::move(prefix_str),
std::move(name_str),
std::move(label_names), "", "1",
false);
i = int_gauges_.emplace(i, std::move(ptr));
}
fptr = i->get();
}
return fptr->get_or_add(labels);
} }
void metric_registry::add_family(metric_type type, std::string prefix, void metric_registry::assert_properties(metric_family* ptr, metric_type type,
std::string name, span<const string_view> label_names,
std::vector<std::string> label_names, string_view unit, bool is_sum) {
std::string helptext, std::string unit, auto labels_match = [&] {
bool is_sum) { const auto& xs = ptr->label_names();
namespace t = caf::telemetry; const auto& ys = label_names;
switch (type) { return std::is_sorted(ys.begin(), ys.end())
case metric_type::int_gauge: ? std::equal(xs.begin(), xs.end(), ys.begin(), ys.end())
add_family<t::int_gauge>(std::move(prefix), std::move(name), : std::is_permutation(xs.begin(), xs.end(), ys.begin(), ys.end());
std::move(label_names), std::move(helptext),
std::move(unit), is_sum);
break;
default:
CAF_RAISE_ERROR("invalid metric type");
}
}
void metric_registry::assert_unregistered(const std::string& prefix,
const std::string& name) {
auto matches = [&](const auto& ptr) {
return ptr->prefix() == prefix && ptr->name() == name;
}; };
if (std::any_of(int_gauges_.begin(), int_gauges_.end(), matches)) if (ptr->type() != type)
CAF_RAISE_ERROR("prefix and name already belong to an int gauge family"); CAF_RAISE_ERROR("full name with different metric type found");
if (!labels_match())
CAF_RAISE_ERROR("full name with different label dimensions found");
if (ptr->unit() != unit)
CAF_RAISE_ERROR("full name with different unit found");
if (ptr->is_sum() != is_sum)
CAF_RAISE_ERROR("full name with different is-sum flag found");
} }
} // namespace caf::telemetry } // namespace caf::telemetry
...@@ -32,6 +32,7 @@ using namespace caf::telemetry; ...@@ -32,6 +32,7 @@ using namespace caf::telemetry;
namespace { namespace {
struct fixture { struct fixture {
using ig = int_gauge;
collector::prometheus exporter; collector::prometheus exporter;
metric_registry registry; metric_registry registry;
}; };
...@@ -41,21 +42,21 @@ struct fixture { ...@@ -41,21 +42,21 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE(prometheus_tests, fixture) CAF_TEST_FIXTURE_SCOPE(prometheus_tests, fixture)
CAF_TEST(the Prometheus collector generates text output) { CAF_TEST(the Prometheus collector generates text output) {
registry.add_family(metric_type::int_gauge, "foo", "bar", {}, auto fb = registry.family<ig>("foo", "bar", {}, "Some value without labels.",
"Just some value without labels.", "seconds"); "seconds");
registry.add_family(metric_type::int_gauge, "some", "value", {"a", "b"}, auto sv = registry.family<ig>("some", "value", {"a", "b"},
"Just some (total) value with two labels.", "1", true); "Some (total) value with two labels.", "1",
registry.add_family(metric_type::int_gauge, "other", "value", {"x"}, "", true);
"seconds", true); auto ov = registry.family<ig>("other", "value", {"x"}, "", "seconds", true);
registry.int_gauge("foo", "bar", {})->value(123); fb->get_or_add({})->value(123);
registry.int_gauge("some", "value", {{"a", "1"}, {"b", "2"}})->value(12); sv->get_or_add({{"a", "1"}, {"b", "2"}})->value(12);
registry.int_gauge("some", "value", {{"b", "1"}, {"a", "2"}})->value(21); sv->get_or_add({{"b", "1"}, {"a", "2"}})->value(21);
registry.int_gauge("other", "value", {{"x", "true"}})->value(31337); ov->get_or_add({{"x", "true"}})->value(31337);
CAF_CHECK_EQUAL(exporter.collect_from(registry, 42), CAF_CHECK_EQUAL(exporter.collect_from(registry, 42),
R"(# HELP foo_bar_seconds Just some value without labels. R"(# HELP foo_bar_seconds Some value without labels.
# TYPE foo_bar_seconds gauge # TYPE foo_bar_seconds gauge
foo_bar_seconds 123 42 foo_bar_seconds 123 42
# HELP some_value_total Just some (total) value with two labels. # HELP some_value_total Some (total) value with two labels.
# TYPE some_value_total gauge # TYPE some_value_total gauge
some_value_total{a="1",b="2"} 12 42 some_value_total{a="1",b="2"} 12 42
some_value_total{a="2",b="1"} 21 42 some_value_total{a="2",b="1"} 21 42
......
...@@ -29,12 +29,12 @@ CAF_TEST(integer gauges can increment and decrement) { ...@@ -29,12 +29,12 @@ CAF_TEST(integer gauges can increment and decrement) {
CAF_MESSAGE("gauges start at 0"); CAF_MESSAGE("gauges start at 0");
CAF_CHECK_EQUAL(g.value(), 0); CAF_CHECK_EQUAL(g.value(), 0);
CAF_MESSAGE("gauges are incrementable"); CAF_MESSAGE("gauges are incrementable");
g.increment(); g.inc();
g.increment(2); g.inc(2);
CAF_CHECK_EQUAL(g.value(), 3); CAF_CHECK_EQUAL(g.value(), 3);
CAF_MESSAGE("gauges are decrementable"); CAF_MESSAGE("gauges are decrementable");
g.decrement(); g.dec();
g.decrement(5); g.dec(5);
CAF_CHECK_EQUAL(g.value(), -3); CAF_CHECK_EQUAL(g.value(), -3);
CAF_MESSAGE("gauges allow setting values"); CAF_MESSAGE("gauges allow setting values");
g.value(42); g.value(42);
......
...@@ -32,7 +32,7 @@ using namespace caf::telemetry; ...@@ -32,7 +32,7 @@ using namespace caf::telemetry;
namespace { namespace {
struct collector { struct test_collector {
std::string result; std::string result;
void operator()(const metric_family* family, const metric* instance, void operator()(const metric_family* family, const metric* instance,
...@@ -70,19 +70,9 @@ struct collector { ...@@ -70,19 +70,9 @@ struct collector {
}; };
struct fixture { struct fixture {
using ig = int_gauge;
metric_registry registry; metric_registry registry;
test_collector collector;
auto bind(string_view prefix, string_view name) {
struct bound {
fixture* self_;
string_view prefix_;
string_view name_;
auto int_gauge(std::vector<label_view> labels) {
return self_->registry.int_gauge(prefix_, name_, std::move(labels));
}
};
return bound{this, prefix, name};
}
}; };
} // namespace } // namespace
...@@ -90,46 +80,53 @@ struct fixture { ...@@ -90,46 +80,53 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE(metric_registry_tests, fixture) CAF_TEST_FIXTURE_SCOPE(metric_registry_tests, fixture)
CAF_TEST(registries lazily create metrics) { CAF_TEST(registries lazily create metrics) {
registry.add_family(metric_type::int_gauge, "caf", "running_actors", auto f = registry.family<ig>("caf", "running_actors", {"var1", "var2"},
{"var1", "var2"}, "How many actors are currently running?");
"How many actors are currently running?");
auto var = bind("caf", "running_actors");
std::vector<label_view> v1{{"var1", "foo"}, {"var2", "bar"}}; std::vector<label_view> v1{{"var1", "foo"}, {"var2", "bar"}};
std::vector<label_view> v1_reversed{{"var2", "bar"}, {"var1", "foo"}}; std::vector<label_view> v1_reversed{{"var2", "bar"}, {"var1", "foo"}};
std::vector<label_view> v2{{"var1", "bar"}, {"var2", "foo"}}; std::vector<label_view> v2{{"var1", "bar"}, {"var2", "foo"}};
std::vector<label_view> v2_reversed{{"var2", "foo"}, {"var1", "bar"}}; std::vector<label_view> v2_reversed{{"var2", "foo"}, {"var1", "bar"}};
var.int_gauge(v1)->value(42); f->get_or_add(v1)->value(42);
var.int_gauge(v2)->value(23); f->get_or_add(v2)->value(23);
CAF_CHECK_EQUAL(var.int_gauge(v1)->value(), 42); CAF_CHECK_EQUAL(f->get_or_add(v1)->value(), 42);
CAF_CHECK_EQUAL(var.int_gauge(v1_reversed)->value(), 42); CAF_CHECK_EQUAL(f->get_or_add(v1_reversed)->value(), 42);
CAF_CHECK_EQUAL(var.int_gauge(v2)->value(), 23); CAF_CHECK_EQUAL(f->get_or_add(v2)->value(), 23);
CAF_CHECK_EQUAL(var.int_gauge(v2_reversed)->value(), 23); CAF_CHECK_EQUAL(f->get_or_add(v2_reversed)->value(), 23);
} }
CAF_TEST(registries allow users to collect all registered metrics) { CAF_TEST(registries allow users to collect all registered metrics) {
registry.add_family(metric_type::int_gauge, "foo", "bar", {}, auto fb = registry.family<ig>("foo", "bar", {}, "Some value without labels.",
"Just some value without labels.", "seconds"); "seconds");
registry.add_family(metric_type::int_gauge, "some", "value", {"a", "b"}, auto sv = registry.family<ig>("some", "value", {"a", "b"},
"Just some (total) value with two labels.", "1", true); "Some (total) value with two labels.", "1",
registry.add_family(metric_type::int_gauge, "other", "value", {"x"}, true);
"Just some (total) seconds value with a labels.", auto ov = registry.family<ig>("other", "value", {"x"},
"seconds", true); "Some (total) seconds with one label.",
registry.add_family(metric_type::int_gauge, "caf", "running_actors", {"node"}, "seconds", true);
"How many actors are currently running?"); auto ra = registry.family<ig>("caf", "running_actors", {"node"},
registry.int_gauge("foo", "bar", {})->value(123); "How many actors are running?");
registry.int_gauge("some", "value", {{"a", "1"}, {"b", "2"}})->value(12); auto ms = registry.family<ig>("caf", "mailbox_size", {"name"},
registry.int_gauge("some", "value", {{"b", "1"}, {"a", "2"}})->value(21); "How full is the mailbox?");
registry.int_gauge("other", "value", {{"x", "true"}})->value(31337); CAF_MESSAGE("the registry always returns the same family object");
auto running_actors = bind("caf", "running_actors"); CAF_CHECK_EQUAL(fb, registry.family<ig>("foo", "bar", {}, "", "seconds"));
running_actors.int_gauge({{"node", "localhost"}})->value(42); CAF_CHECK_EQUAL(sv, registry.family<ig>("some", "value", {"a", "b"}, "", "1",
// Note: not registering caf_mailbox_size previously forces CAF to create it true));
// lazily when adding the first gauge. CAF_CHECK_EQUAL(sv, registry.family<ig>("some", "value", {"b", "a"}, "", "1",
auto mailbox_size = bind("caf", "mailbox_size"); true));
mailbox_size.int_gauge({{"name", "printer"}})->value(3); CAF_MESSAGE("families always return the same metric object for given labels");
mailbox_size.int_gauge({{"name", "parser"}})->value(12); CAF_CHECK_EQUAL(fb->get_or_add({}), fb->get_or_add({}));
collector c; CAF_CHECK_EQUAL(sv->get_or_add({{"a", "1"}, {"b", "2"}}),
registry.collect(c); sv->get_or_add({{"b", "2"}, {"a", "1"}}));
CAF_CHECK_EQUAL(c.result, R"( CAF_MESSAGE("collectors can observe all metrics in the registry");
fb->get_or_add({})->inc(123);
sv->get_or_add({{"a", "1"}, {"b", "2"}})->value(12);
sv->get_or_add({{"b", "1"}, {"a", "2"}})->value(21);
ov->get_or_add({{"x", "true"}})->value(31337);
ra->get_or_add({{"node", "localhost"}})->value(42);
ms->get_or_add({{"name", "printer"}})->value(3);
ms->get_or_add({{"name", "parser"}})->value(12);
registry.collect(collector);
CAF_CHECK_EQUAL(collector.result, R"(
foo_bar_seconds 123 foo_bar_seconds 123
some_value_total{a="1",b="2"} 12 some_value_total{a="1",b="2"} 12
some_value_total{a="2",b="1"} 21 some_value_total{a="2",b="1"} 21
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment