Branch data Line data Source code
1 : : // Copyright 2026 HPActor Contributors
2 : : //
3 : : // Licensed under the Apache License, Version 2.0 (the "License");
4 : : // you may not use this file except in compliance with the License.
5 : : // You may obtain a copy of the License at
6 : : //
7 : : // http://www.apache.org/licenses/LICENSE-2.0
8 : : //
9 : : // Unless required by applicable law or agreed to in writing, software
10 : : // distributed under the License is distributed on an "AS IS" BASIS,
11 : : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : // See the License for the specific language governing permissions and
13 : : // limitations under the License.
14 : :
15 : : #include <hpactor/metrics/metrics_registry.hpp>
16 : :
17 : : #include <algorithm>
18 : : #include <tuple>
19 : :
20 : : namespace hpactor::metrics {
21 : :
22 : 3 : void HistogramValue::observe(uint64_t value_ns) noexcept {
23 : 3 : uint64_t ms = value_ns / 1'000'000;
24 : 3 : int idx = 0;
25 : 3 : if (ms > 1) {
26 : 2 : idx = 64 - __builtin_clzll(ms - 1);
27 : 2 : idx = std::max(0, idx);
28 : : }
29 : 3 : if (idx >= static_cast<int>(kHistogramNumBuckets)) {
30 : 0 : idx = kHistogramNumBuckets - 1;
31 : : }
32 : 3 : buckets[idx].fetch_add(1, std::memory_order_relaxed);
33 : 3 : count.fetch_add(1, std::memory_order_relaxed);
34 : 3 : sum_ns.fetch_add(value_ns, std::memory_order_relaxed);
35 : 3 : }
36 : :
37 : 4 : bool LabelSet::operator==(const LabelSet& other) const {
38 : 4 : if (metric_name != other.metric_name) return false;
39 : 4 : return labels == other.labels;
40 : : }
41 : :
42 : 34 : size_t LabelSetHash::operator()(const LabelSet& ls) const {
43 : 34 : size_t h = std::hash<std::string>()(ls.metric_name);
44 : 70 : for (const auto& [k, v] : ls.labels) {
45 : 36 : h ^= std::hash<std::string>()(k) + 0x9e3779b9 + (h << 6) + (h >> 2);
46 : 36 : h ^= std::hash<std::string>()(v) + 0x9e3779b9 + (h << 6) + (h >> 2);
47 : : }
48 : 34 : return h;
49 : : }
50 : :
51 : 161 : MetricFamily& MetricRegistry::register_family(std::string name, std::string help,
52 : : MetricType type) {
53 : 161 : auto it = family_index_.find(name);
54 : 161 : if (it != family_index_.end()) {
55 : 1 : return *it->second;
56 : : }
57 : 160 : auto family = std::make_unique<MetricFamily>();
58 : 160 : family->name = name;
59 : 160 : family->help = std::move(help);
60 : 160 : family->type = type;
61 : 160 : MetricFamily* ptr = family.get();
62 : 160 : family_index_[name] = ptr;
63 : 160 : families_.push_back(std::move(family));
64 : 160 : return *ptr;
65 : 160 : }
66 : :
67 : : template <typename V>
68 : 34 : V& MetricRegistry::get_or_create(MetricFamily& family, const LabelSet& labels) {
69 : 34 : auto it = family.values.find(labels);
70 : 34 : if (it != family.values.end()) {
71 : 4 : return std::get<V>(it->second);
72 : : }
73 : 30 : auto [inserted, _] = family.values.emplace(
74 : : std::piecewise_construct,
75 : : std::forward_as_tuple(labels),
76 : : std::forward_as_tuple(std::in_place_type<V>));
77 : 30 : return std::get<V>(inserted->second);
78 : : }
79 : :
80 : : template CounterValue& MetricRegistry::get_or_create<CounterValue>(MetricFamily&, const LabelSet&);
81 : : template GaugeValue& MetricRegistry::get_or_create<GaugeValue>(MetricFamily&, const LabelSet&);
82 : : template HistogramValue& MetricRegistry::get_or_create<HistogramValue>(MetricFamily&, const LabelSet&);
83 : :
84 : 8 : MetricRegistry::Snapshot MetricRegistry::snapshot() const {
85 : 8 : Snapshot snap;
86 : 62 : for (const auto& family : families_) {
87 : 54 : Snapshot::FamilySnapshot fs;
88 : 54 : fs.name = family->name;
89 : 54 : fs.help = family->help;
90 : 54 : fs.type = family->type;
91 : :
92 : 69 : for (const auto& [ls, val] : family->values) {
93 : 15 : switch (family->type) {
94 : 5 : case MetricType::kCounter: {
95 : 5 : uint64_t v = std::get<CounterValue>(val).total.load(std::memory_order_relaxed);
96 : 5 : fs.counters.emplace_back(ls, v);
97 : 5 : break;
98 : : }
99 : 7 : case MetricType::kGauge: {
100 : 7 : int64_t v = std::get<GaugeValue>(val).value.load(std::memory_order_relaxed);
101 : 7 : fs.gauges.emplace_back(ls, v);
102 : 7 : break;
103 : : }
104 : 3 : case MetricType::kHistogram: {
105 : 3 : const auto& hv = std::get<HistogramValue>(val);
106 : 3 : Snapshot::HistogramEntry he;
107 : 3 : he.labels = ls;
108 : 3 : he.count = hv.count.load(std::memory_order_relaxed);
109 : 3 : he.sum_seconds = static_cast<double>(hv.sum_ns.load(std::memory_order_relaxed)) / 1e9;
110 : 51 : for (size_t i = 0; i < kHistogramNumBuckets; ++i) {
111 : 96 : he.buckets[i] = hv.buckets[i].load(std::memory_order_relaxed);
112 : : }
113 : 3 : fs.histograms.push_back(std::move(he));
114 : 3 : break;
115 : 3 : }
116 : : }
117 : : }
118 : 54 : snap.families.push_back(std::move(fs));
119 : 54 : }
120 : 8 : return snap;
121 : : }
122 : :
123 : : } // namespace hpactor::metrics
|