userver: userver/utils/statistics/aggregated_values.hpp Source File
Loading...
Searching...
No Matches
aggregated_values.hpp
1#pragma once
2
3#include <array>
4#include <atomic>
5
6#include <fmt/compile.h>
7#include <fmt/format.h>
8
9#include <userver/formats/json/value_builder.hpp>
10#include <userver/utils/assert.hpp>
11#include <userver/utils/datetime.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace utils::statistics {
16
17/// Timing values aggregated into buckets, each bucket is from 2**k to 2**(k+1)
18/// Values out of range are put into last bucket.
19template <size_t Length>
20struct AggregatedValues final {
21 std::array<std::atomic_llong, Length> value{{}};
22
23 AggregatedValues& operator=(const AggregatedValues& other) {
24 if (this == &other) return *this;
25
26 for (size_t i = 0; i < value.size(); ++i) value[i] = other.value[i].load();
27 return *this;
28 }
29
30 AggregatedValues& operator+=(const AggregatedValues& other) {
31 for (size_t i = 0; i < value.size(); ++i) value[i] += other.value[i].load();
32 return *this;
33 }
34
35 void Add(size_t key, size_t delta);
36
37 long long Get(size_t bucket) const;
38};
39
40template <size_t Length>
41void AggregatedValues<Length>::Add(size_t key, size_t delta) {
42 size_t bucket = 0;
43 while (key > 1) {
44 bucket++;
45 key >>= 1;
46 }
47 if (bucket >= Length) bucket = Length - 1;
48
49 value[bucket] += delta;
50}
51
52template <size_t Length>
53long long AggregatedValues<Length>::Get(size_t bucket) const {
54 UASSERT(bucket < value.size());
55 return value[bucket].load();
56}
57
58/// TODO: convert to histogram for Solomon
59template <size_t length>
60formats::json::Value AggregatedValuesToJson(
61 const AggregatedValues<length>& stats, const std::string& suffix = {}) {
62 formats::json::ValueBuilder result(formats::json::Type::kObject);
63 for (size_t i = 0; i < length; ++i) {
64 auto l = i ? (1 << i) : 0;
65 auto r = (1 << (i + 1)) - 1;
66
67 std::string key;
68 if (i != length - 1) {
69 key = fmt::format(FMT_COMPILE("{}-{}{}"), l, r, suffix);
70 } else {
71 key = fmt::format(FMT_COMPILE("{}-x{}"), l, suffix);
72 }
73 result[key] = stats.value[i].load();
74 }
75 return result.ExtractValue();
76}
77
78template <size_t Length>
79formats::json::Value AggregatedValuesToJson(
80 const AggregatedValues<Length>& stats) {
81 formats::json::ValueBuilder result(formats::json::Type::kObject);
82 for (size_t i = 0; i < Length; ++i) {
83 auto l = i ? (1 << i) : 0;
84 auto r = (1 << (i + 1)) - 1;
85 std::string key;
86 if (i < Length - 1) {
87 key = fmt::format(FMT_COMPILE("{}-{}"), l, r);
88 } else {
89 key = fmt::format(FMT_COMPILE("{}-x"), l);
90 }
91 result[key] = stats.Get(i);
92 }
93 return result.ExtractValue();
94}
95
96} // namespace utils::statistics
97
98USERVER_NAMESPACE_END