Commit b7f4a3f6 authored by Dominik Charousset's avatar Dominik Charousset

Make bucket sizes configurable

parent 4dc849fa
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/raise_error.hpp" #include "caf/raise_error.hpp"
#include "caf/settings.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
#include "caf/telemetry/gauge.hpp" #include "caf/telemetry/gauge.hpp"
#include "caf/telemetry/histogram.hpp" #include "caf/telemetry/histogram.hpp"
...@@ -134,7 +135,9 @@ public: ...@@ -134,7 +135,9 @@ public:
/// reserved. /// reserved.
/// @param name The human-readable name of the metric, e.g., `requests`. /// @param name The human-readable name of the metric, e.g., `requests`.
/// @param label_names Names for all label dimensions of the metric. /// @param label_names Names for all label dimensions of the metric.
/// @param upper_bounds Upper bounds for the metric buckets. /// @param default_upper_bounds Upper bounds for the metric buckets.
/// @param metrics_settings Runtime parameters that may override
/// `default_upper_bounds`. May be `nullptr`.
/// @param helptext Short explanation of the metric. /// @param helptext Short explanation of the metric.
/// @param unit Unit of measurement. Please use base units such as `bytes` or /// @param unit Unit of measurement. Please use base units such as `bytes` or
/// `seconds` (prefer lowercase). The pseudo-unit `1` identifies /// `seconds` (prefer lowercase). The pseudo-unit `1` identifies
...@@ -142,25 +145,38 @@ public: ...@@ -142,25 +145,38 @@ public:
/// @param is_sum Setting this to `true` indicates that this metric adds /// @param is_sum Setting this to `true` indicates that this metric adds
/// 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.
/// @note The first call wins when calling this function multiple times with
/// different bucket settings. Later calls skip checking the bucket
/// settings, mainly because this check would be rather expensive.
template <class ValueType = int64_t> template <class ValueType = int64_t>
metric_family_impl<histogram<ValueType>>* histogram_family( metric_family_impl<histogram<ValueType>>* histogram_family(
string_view prefix, string_view name, span<const string_view> label_names, string_view prefix, string_view name, span<const string_view> label_names,
span<const typename histogram<ValueType>::value_type> upper_bounds, span<const typename histogram<ValueType>::value_type> default_upper_bounds,
string_view helptext, string_view unit = "1", bool is_sum = false) { const settings* metrics_settings, string_view helptext,
if (upper_bounds.empty()) string_view unit = "1", bool is_sum = false) {
CAF_RAISE_ERROR("at least one bucket must exist");
using histogram_type = histogram<ValueType>; using histogram_type = histogram<ValueType>;
using family_type = metric_family_impl<histogram_type>; using family_type = metric_family_impl<histogram_type>;
using upper_bounds_list = std::vector<ValueType>;
if (default_upper_bounds.empty())
CAF_RAISE_ERROR("at least one bucket must exist in the default settings");
std::unique_lock<std::mutex> guard{families_mx_}; std::unique_lock<std::mutex> guard{families_mx_};
if (auto ptr = fetch(prefix, name)) { if (auto ptr = fetch(prefix, name)) {
assert_histogram_properties(ptr, histogram_type::runtime_type, assert_properties(ptr, histogram_type::runtime_type, label_names, unit,
label_names, upper_bounds, unit, is_sum); is_sum);
return static_cast<family_type*>(ptr); return static_cast<family_type*>(ptr);
} }
upper_bounds_list upper_bounds;
if (metrics_settings != nullptr)
if (auto grp = get_if<settings>(metrics_settings, name))
if (auto var = get_if<settings>(grp, name))
if (auto lst = get_if<upper_bounds_list>(var, "buckets"))
upper_bounds = std::move(*lst);
if (upper_bounds.empty())
upper_bounds.assign(default_upper_bounds.begin(),
default_upper_bounds.end());
auto ptr = std::make_unique<family_type>( auto ptr = std::make_unique<family_type>(
to_string(prefix), to_string(name), to_sorted_vec(label_names), to_string(prefix), to_string(name), to_sorted_vec(label_names),
to_string(helptext), to_string(unit), is_sum, upper_bounds.begin(), to_string(helptext), to_string(unit), is_sum, std::move(upper_bounds));
upper_bounds.end());
auto& families = container_by_type<histogram_type>(); auto& families = container_by_type<histogram_type>();
families.emplace_back(std::move(ptr)); families.emplace_back(std::move(ptr));
return families.back().get(); return families.back().get();
...@@ -172,10 +188,12 @@ public: ...@@ -172,10 +188,12 @@ public:
string_view prefix, string_view name, string_view prefix, string_view name,
std::initializer_list<string_view> label_names, std::initializer_list<string_view> label_names,
span<const typename histogram<ValueType>::value_type> upper_bounds, span<const typename histogram<ValueType>::value_type> upper_bounds,
string_view helptext, string_view unit = "1", bool is_sum = false) { const settings* metrics_settings, string_view helptext,
string_view unit = "1", bool is_sum = false) {
auto lbl_span = make_span(label_names.begin(), label_names.size()); auto lbl_span = make_span(label_names.begin(), label_names.size());
return histogram_family<ValueType>(prefix, name, lbl_span, upper_bounds, return histogram_family<ValueType>(prefix, name, lbl_span, upper_bounds,
helptext, unit, is_sum); metrics_settings, helptext, unit,
is_sum);
} }
/// Returns a histogram metric singleton, i.e., the single instance of a /// Returns a histogram metric singleton, i.e., the single instance of a
...@@ -238,20 +256,6 @@ private: ...@@ -238,20 +256,6 @@ private:
span<const string_view> label_names, string_view unit, span<const string_view> label_names, string_view unit,
bool is_sum); bool is_sum);
template <class ValueType>
void assert_histogram_properties(const metric_family* ptr, metric_type type,
span<const string_view> label_names,
span<const ValueType> upper_bounds,
string_view unit, bool is_sum) {
assert_properties(ptr, type, label_names, unit, is_sum);
using family_type = metric_family_impl<histogram<ValueType>>;
auto dptr = static_cast<const family_type*>(ptr);
auto& xs = dptr->extra_setting();
if (!std::equal(xs.begin(), xs.end(), upper_bounds.begin(),
upper_bounds.end()))
CAF_RAISE_ERROR("full name with different bucket settings found");
}
template <class Type> template <class Type>
metric_family_container<Type>& container_by_type(); metric_family_container<Type>& container_by_type();
......
...@@ -49,7 +49,8 @@ CAF_TEST(the Prometheus collector generates text output) { ...@@ -49,7 +49,8 @@ CAF_TEST(the Prometheus collector generates text output) {
auto ov = registry.gauge_family("other", "value", {"x"}, "", "seconds", true); auto ov = registry.gauge_family("other", "value", {"x"}, "", "seconds", true);
std::vector<int64_t> upper_bounds{1, 2, 4}; std::vector<int64_t> upper_bounds{1, 2, 4};
auto sr = registry.histogram_family("some", "request-duration", {"x"}, auto sr = registry.histogram_family("some", "request-duration", {"x"},
upper_bounds, "Some help.", "seconds"); upper_bounds, nullptr, "Some help.",
"seconds");
fb->get_or_add({})->value(123); fb->get_or_add({})->value(123);
sv->get_or_add({{"a", "1"}, {"b", "2"}})->value(12); sv->get_or_add({{"a", "1"}, {"b", "2"}})->value(12);
sv->get_or_add({{"b", "1"}, {"a", "2"}})->value(21); sv->get_or_add({{"b", "1"}, {"a", "2"}})->value(21);
......
...@@ -101,7 +101,8 @@ CAF_TEST(registries lazily create metrics) { ...@@ -101,7 +101,8 @@ CAF_TEST(registries lazily create metrics) {
auto f = registry.gauge_family("caf", "running-actors", {"var1", "var2"}, auto f = registry.gauge_family("caf", "running-actors", {"var1", "var2"},
"How many actors are currently running?"); "How many actors are currently running?");
auto g = registry.histogram_family("caf", "response-time", {"var1", "var2"}, auto g = registry.histogram_family("caf", "response-time", {"var1", "var2"},
upper_bounds, "How long take requests?"); upper_bounds, nullptr,
"How long take requests?");
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"}};
...@@ -162,4 +163,15 @@ caf.mailbox-size{name="printer"} 3 ...@@ -162,4 +163,15 @@ caf.mailbox-size{name="printer"} 3
caf.mailbox-size{name="parser"} 12)"); caf.mailbox-size{name="parser"} 12)");
} }
CAF_TEST(buckets for histograms are configurable via runtime settings){
settings cfg;
std::vector<int64_t> default_upper_bounds{1, 2, 4, 8};
std::vector<int64_t> upper_bounds{1, 2, 3, 5, 7};
put(cfg, "caf.response-time.buckets", upper_bounds);
auto h = registry.histogram_family("caf", "response-time", {"var1", "var2"},
upper_bounds, &cfg,
"How long take requests?");
CAF_CHECK_EQUAL(h->extra_setting(), upper_bounds);
}
CAF_TEST_FIXTURE_SCOPE_END() CAF_TEST_FIXTURE_SCOPE_END()
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