40 typename std::remove_cvref_t<T>::ValueType;
42 { t.observe(
typename std::remove_cvref_t<T>::ValueType{1}) } -> std::same_as<void>;
44 t.setBuckets(std::vector<
typename std::remove_cvref_t<T>::ValueType>{})
45 } -> std::same_as<void>;
47 t.serializeValue(std::string{}, std::string{}, std::declval<OStream&>())
48 } -> std::same_as<void>;
54 using ValueType = NumberType;
56 HistogramImpl() =
default;
58 HistogramImpl(HistogramImpl
const&) =
delete;
59 HistogramImpl(HistogramImpl&&) =
default;
62 operator=(HistogramImpl
const&) =
delete;
64 operator=(HistogramImpl&&) =
default;
67 setBuckets(std::vector<ValueType>
const& bounds)
69 auto data = data_->template lock<std::scoped_lock>();
70 ASSERT(
data->buckets.empty(),
"Buckets can be set only once.");
71 data->buckets.reserve(bounds.size());
72 for (
auto const& bound : bounds) {
73 data->buckets.emplace_back(bound);
78 observe(ValueType
const value)
80 auto data = data_->template lock<std::scoped_lock>();
81 auto const bucket = std::lower_bound(
82 data->buckets.begin(),
85 [](Bucket
const& bucket, ValueType
const& value) { return bucket.upperBound < value; }
87 if (bucket !=
data->buckets.end()) {
90 ++
data->lastBucket.count;
96 serializeValue(std::string
const& name, std::string labelsString,
OStream& stream)
const
98 if (labelsString.empty()) {
102 labelsString.front() ==
'{' && labelsString.back() ==
'}',
103 "Labels must be in Prometheus serialized format."
105 labelsString.back() =
',';
108 auto data = data_->template lock<std::scoped_lock>();
109 std::uint64_t cumulativeCount = 0;
111 for (
auto const& bucket :
data->buckets) {
112 cumulativeCount += bucket.count;
113 stream << name <<
"_bucket" << labelsString <<
"le=\"" << bucket.upperBound <<
"\"} "
114 << cumulativeCount <<
'\n';
116 cumulativeCount +=
data->lastBucket.count;
117 stream << name <<
"_bucket" << labelsString <<
"le=\"+Inf\"} " << cumulativeCount <<
'\n';
119 if (labelsString.size() == 1) {
122 labelsString.back() =
'}';
124 stream << name <<
"_sum" << labelsString <<
" " <<
data->sum <<
'\n';
125 stream << name <<
"_count" << labelsString <<
" " << cumulativeCount <<
'\n';
130 Bucket(ValueType upperBound) : upperBound(upperBound)
134 ValueType upperBound;
135 std::uint64_t count = 0;
139 std::vector<Bucket> buckets;
140 Bucket lastBucket{std::numeric_limits<ValueType>::max()};
143 std::unique_ptr<util::Mutex<Data>> data_ = std::make_unique<util::Mutex<Data>>();