21 typename std::remove_cvref_t<T>::ValueType;
23 { t.observe(
typename std::remove_cvref_t<T>::ValueType{1}) } -> std::same_as<void>;
25 t.setBuckets(std::vector<
typename std::remove_cvref_t<T>::ValueType>{})
26 } -> std::same_as<void>;
28 t.serializeValue(std::string{}, std::string{}, std::declval<OStream&>())
29 } -> std::same_as<void>;
35 using ValueType = NumberType;
37 HistogramImpl() =
default;
39 HistogramImpl(HistogramImpl
const&) =
delete;
40 HistogramImpl(HistogramImpl&&) =
default;
43 operator=(HistogramImpl
const&) =
delete;
45 operator=(HistogramImpl&&) =
default;
48 setBuckets(std::vector<ValueType>
const& bounds)
50 auto data = data_->template lock<std::scoped_lock>();
51 ASSERT(
data->buckets.empty(),
"Buckets can be set only once.");
52 data->buckets.reserve(bounds.size());
53 for (
auto const& bound : bounds) {
54 data->buckets.emplace_back(bound);
59 observe(ValueType
const value)
61 auto data = data_->template lock<std::scoped_lock>();
62 auto const bucket = std::lower_bound(
63 data->buckets.begin(),
66 [](Bucket
const& bucket, ValueType
const& value) { return bucket.upperBound < value; }
68 if (bucket !=
data->buckets.end()) {
71 ++
data->lastBucket.count;
77 serializeValue(std::string
const& name, std::string labelsString,
OStream& stream)
const
79 if (labelsString.empty()) {
83 labelsString.front() ==
'{' && labelsString.back() ==
'}',
84 "Labels must be in Prometheus serialized format."
86 labelsString.back() =
',';
89 auto data = data_->template lock<std::scoped_lock>();
90 std::uint64_t cumulativeCount = 0;
92 for (
auto const& bucket :
data->buckets) {
93 cumulativeCount += bucket.count;
94 stream << name <<
"_bucket" << labelsString <<
"le=\"" << bucket.upperBound <<
"\"} "
95 << cumulativeCount <<
'\n';
97 cumulativeCount +=
data->lastBucket.count;
98 stream << name <<
"_bucket" << labelsString <<
"le=\"+Inf\"} " << cumulativeCount <<
'\n';
100 if (labelsString.size() == 1) {
103 labelsString.back() =
'}';
105 stream << name <<
"_sum" << labelsString <<
" " <<
data->sum <<
'\n';
106 stream << name <<
"_count" << labelsString <<
" " << cumulativeCount <<
'\n';
111 Bucket(ValueType upperBound) : upperBound(upperBound)
115 ValueType upperBound;
116 std::uint64_t count = 0;
120 std::vector<Bucket> buckets;
121 Bucket lastBucket{std::numeric_limits<ValueType>::max()};
124 std::unique_ptr<util::Mutex<Data>> data_ = std::make_unique<util::Mutex<Data>>();