#include using namespace drogon; using namespace drogon::monitoring; void Histogram::observe(double value) { std::lock_guard lock(mutex_); if (maxAge_ > std::chrono::seconds(0) && timerId_ == trantor::InvalidTimerId) { std::weak_ptr weakPtr = std::dynamic_pointer_cast(shared_from_this()); timerId_ = loopPtr_->runEvery(maxAge_ / timeBucketCount_, [weakPtr]() { auto thisPtr = weakPtr.lock(); if (!thisPtr) return; thisPtr->rotateTimeBuckets(); }); } auto ¤tBucket = timeBuckets_.back(); currentBucket.sum += value; currentBucket.count += 1; for (size_t i = 0; i < bucketBoundaries_.size(); i++) { if (value <= bucketBoundaries_[i]) { currentBucket.buckets[i] += 1; break; } } if (value > bucketBoundaries_.back()) { currentBucket.buckets.back() += 1; } } std::vector Histogram::collect() const { std::vector samples; std::lock_guard guard(mutex_); size_t count{0}; for (size_t i = 0; i < bucketBoundaries_.size(); i++) { Sample sample; for (auto &bucket : timeBuckets_) { count += bucket.buckets[i]; } sample.name = name_ + "_bucket"; sample.exLabels.emplace_back("le", std::to_string(bucketBoundaries_[i])); sample.value = count; samples.emplace_back(std::move(sample)); } Sample sample; for (auto &bucket : timeBuckets_) { count += bucket.buckets.back(); } sample.name = name_ + "_bucket"; sample.exLabels.emplace_back("le", "+Inf"); sample.value = count; samples.emplace_back(std::move(sample)); double sum{0}; uint64_t totalCount{0}; for (auto &bucket : timeBuckets_) { sum += bucket.sum; totalCount += bucket.count; } Sample sumSample; sumSample.name = name_ + "_sum"; sumSample.value = sum; samples.emplace_back(std::move(sumSample)); Sample countSample; countSample.name = name_ + "_count"; countSample.value = totalCount; samples.emplace_back(std::move(countSample)); return samples; }