userver: userver/utils/statistics/aggregated_values.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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