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/actor/abstract_actor.hpp>
16 : : #include <hpactor/core/actor_system.hpp>
17 : : #include <hpactor/metrics/metrics_aggregator.hpp>
18 : : #include <string>
19 : :
20 : : namespace hpactor::metrics {
21 : :
22 : 11 : Aggregator::Aggregator(MetricRegistry& registry, ActorSystem& system)
23 : 11 : : registry_(registry), system_(system) {}
24 : :
25 : 32 : void Aggregator::ensure_families_registered() {
26 : 32 : if (mailbox_depth_family_)
27 : 21 : return;
28 : 44 : mailbox_depth_family_ = ®istry_.register_family("hpactor_mailbox_depth",
29 : : "Current mailbox queue "
30 : : "depth.",
31 : : MetricType::kGauge);
32 : 44 : mailbox_messages_family_ = ®istry_.register_family("hpactor_mailbox_"
33 : : "messages_total",
34 : : "Total messages "
35 : : "enqueued.",
36 : : MetricType::kCounter);
37 : 44 : processing_latency_family_ = ®istry_.register_family(
38 : : "hpactor_message_processing_seconds", "Message processing latency.",
39 : : MetricType::kHistogram);
40 : 44 : lifecycle_family_ = ®istry_.register_family("hpactor_actor_lifecycle_"
41 : : "total",
42 : : "Actor lifecycle events.",
43 : : MetricType::kCounter);
44 : 11 : scheduler_dispatch_family_ =
45 : 44 : ®istry_.register_family("hpactor_scheduler_dispatches_total",
46 : : "Scheduler dispatches.", MetricType::kCounter);
47 : 44 : scheduler_steal_family_ = ®istry_.register_family(
48 : : "hpactor_scheduler_steals_total", "Work steals.", MetricType::kCounter);
49 : 11 : supervisor_restart_family_ =
50 : 44 : ®istry_.register_family("hpactor_supervisor_restarts_total",
51 : : "Actor restarts.", MetricType::kCounter);
52 : 44 : memory_bytes_family_ = ®istry_.register_family("hpactor_memory_active_"
53 : : "bytes",
54 : : "Active allocated bytes.",
55 : : MetricType::kGauge);
56 : 44 : mailbox_rejected_family_ = ®istry_.register_family("hpactor_mailbox_"
57 : : "rejected_total",
58 : : "Mailbox admission "
59 : : "rejections.",
60 : : MetricType::kCounter);
61 : 44 : mailbox_dropped_family_ = ®istry_.register_family("hpactor_mailbox_"
62 : : "dropped_total",
63 : : "Mailbox policy "
64 : : "drops.",
65 : : MetricType::kCounter);
66 : 44 : mailbox_dead_letter_family_ = ®istry_.register_family("hpactor_mailbox_"
67 : : "dead_letters_"
68 : : "total",
69 : : "Mailbox messages "
70 : : "routed to dead "
71 : : "letters.",
72 : : MetricType::kCounter);
73 : 44 : backpressure_signal_family_ = ®istry_.register_family("hpactor_"
74 : : "backpressure_"
75 : : "signals_total",
76 : : "Backpressure "
77 : : "signals emitted.",
78 : : MetricType::kCounter);
79 : 55 : dead_letter_lost_family_ = ®istry_.register_family("hpactor_dead_letter_"
80 : : "lost_total",
81 : : "Dead-letter records "
82 : : "lost.",
83 : : MetricType::kCounter);
84 : : }
85 : :
86 : 13 : LabelSet Aggregator::make_actor_labels(ActorId id) {
87 : 13 : LabelSet ls;
88 : 13 : std::string type_name;
89 : :
90 : 13 : auto it = actor_type_cache_.find(id);
91 : 13 : if (it != actor_type_cache_.end()) {
92 : 6 : type_name = it->second;
93 : : } else {
94 : 7 : auto actor = system_.get_actor(id);
95 : 21 : type_name = actor ? std::string(actor->type_name()) : "unknown";
96 : 7 : actor_type_cache_[id] = type_name;
97 : 7 : }
98 : :
99 : 13 : ls.labels.emplace_back("actor_id", std::to_string(id.value()));
100 : 13 : ls.labels.emplace_back("actor_type", type_name);
101 : 13 : return ls;
102 : 13 : }
103 : :
104 : 12 : void Aggregator::begin_drain() {
105 : 12 : ensure_families_registered();
106 : 12 : }
107 : :
108 : 12 : void Aggregator::end_drain() {
109 : 12 : LabelSet ls;
110 : 48 : auto& active_family = registry_.register_family("hpactor_actors_active",
111 : : "Number of currently "
112 : : "active actors.",
113 : : MetricType::kGauge);
114 : 12 : auto& g = registry_.get_or_create<GaugeValue>(active_family, ls);
115 : 12 : g.value.store(active_actors_, std::memory_order_relaxed);
116 : 12 : }
117 : :
118 : 20 : void Aggregator::on_event(const MetricEvent& e) {
119 : 20 : ensure_families_registered();
120 : :
121 : 20 : switch (e.event_type) {
122 : 1 : case MetricEventType::kMailboxEnqueue: {
123 : 1 : auto lb = make_actor_labels(e.actor_id);
124 : : {
125 : : auto& g =
126 : 1 : registry_.get_or_create<GaugeValue>(*mailbox_depth_family_, lb);
127 : 1 : g.value.fetch_add(1, std::memory_order_relaxed);
128 : : }
129 : : {
130 : 1 : auto& c = registry_.get_or_create<CounterValue>(
131 : 1 : *mailbox_messages_family_, lb);
132 : 1 : c.total.fetch_add(1, std::memory_order_relaxed);
133 : : }
134 : 1 : break;
135 : 1 : }
136 : 1 : case MetricEventType::kMailboxDequeue: {
137 : 2 : auto& g = registry_.get_or_create<GaugeValue>(
138 : 1 : *mailbox_depth_family_, make_actor_labels(e.actor_id));
139 : 1 : g.value.fetch_sub(1, std::memory_order_relaxed);
140 : 1 : break;
141 : : }
142 : 1 : case MetricEventType::kMessageProcessed: {
143 : 2 : auto& h = registry_.get_or_create<HistogramValue>(
144 : 1 : *processing_latency_family_, make_actor_labels(e.actor_id));
145 : 1 : h.observe(e.value_hi);
146 : 1 : break;
147 : : }
148 : 1 : case MetricEventType::kActorSpawned:
149 : 1 : active_actors_++;
150 : : [[fallthrough]];
151 : 2 : case MetricEventType::kActorTerminated: {
152 : 2 : if (e.event_type == MetricEventType::kActorTerminated)
153 : 1 : active_actors_--;
154 : 4 : auto& c = registry_.get_or_create<CounterValue>(
155 : 2 : *lifecycle_family_, make_actor_labels(e.actor_id));
156 : 2 : c.total.fetch_add(1, std::memory_order_relaxed);
157 : 2 : break;
158 : : }
159 : 1 : case MetricEventType::kSchedulerDispatch: {
160 : 1 : LabelSet ls;
161 : 1 : ls.labels.emplace_back("worker_id", std::to_string(e.value_hi));
162 : 1 : auto& c = registry_.get_or_create<CounterValue>(
163 : 1 : *scheduler_dispatch_family_, ls);
164 : 1 : c.total.fetch_add(1, std::memory_order_relaxed);
165 : 1 : break;
166 : 1 : }
167 : 1 : case MetricEventType::kSchedulerSteal: {
168 : 1 : LabelSet ls;
169 : 1 : ls.labels.emplace_back("source_worker", std::to_string(e.value_hi));
170 : : auto& c =
171 : 1 : registry_.get_or_create<CounterValue>(*scheduler_steal_family_, ls);
172 : 1 : c.total.fetch_add(1, std::memory_order_relaxed);
173 : 1 : break;
174 : 1 : }
175 : 1 : case MetricEventType::kSupervisorRestart: {
176 : 2 : auto& c = registry_.get_or_create<CounterValue>(
177 : 1 : *supervisor_restart_family_, make_actor_labels(e.actor_id));
178 : 1 : c.total.fetch_add(1, std::memory_order_relaxed);
179 : 1 : break;
180 : : }
181 : 1 : case MetricEventType::kMemoryAlloc: {
182 : 2 : auto& g = registry_.get_or_create<GaugeValue>(
183 : 1 : *memory_bytes_family_, make_actor_labels(e.actor_id));
184 : 1 : g.value.fetch_add(static_cast<int64_t>(e.value_hi),
185 : : std::memory_order_relaxed);
186 : 1 : break;
187 : : }
188 : 1 : case MetricEventType::kMemoryFree: {
189 : 2 : auto& g = registry_.get_or_create<GaugeValue>(
190 : 1 : *memory_bytes_family_, make_actor_labels(e.actor_id));
191 : 1 : g.value.fetch_sub(static_cast<int64_t>(e.value_hi),
192 : : std::memory_order_relaxed);
193 : 1 : break;
194 : : }
195 : 1 : case MetricEventType::kMailboxRejected: {
196 : 2 : auto& c = registry_.get_or_create<CounterValue>(
197 : 1 : *mailbox_rejected_family_, make_actor_labels(e.actor_id));
198 : 1 : c.total.fetch_add(1, std::memory_order_relaxed);
199 : 1 : break;
200 : : }
201 : 1 : case MetricEventType::kMailboxDropped: {
202 : 2 : auto& c = registry_.get_or_create<CounterValue>(
203 : 1 : *mailbox_dropped_family_, make_actor_labels(e.actor_id));
204 : 1 : c.total.fetch_add(1, std::memory_order_relaxed);
205 : 1 : break;
206 : : }
207 : 1 : case MetricEventType::kMailboxDeadLetter: {
208 : 2 : auto& c = registry_.get_or_create<CounterValue>(
209 : 1 : *mailbox_dead_letter_family_, make_actor_labels(e.actor_id));
210 : 1 : c.total.fetch_add(1, std::memory_order_relaxed);
211 : 1 : break;
212 : : }
213 : 1 : case MetricEventType::kBackpressureSignal: {
214 : 2 : auto& c = registry_.get_or_create<CounterValue>(
215 : 1 : *backpressure_signal_family_, make_actor_labels(e.actor_id));
216 : 1 : c.total.fetch_add(1, std::memory_order_relaxed);
217 : 1 : break;
218 : : }
219 : 1 : case MetricEventType::kDeadLetterLost: {
220 : 2 : auto& c = registry_.get_or_create<CounterValue>(
221 : 1 : *dead_letter_lost_family_, make_actor_labels(e.actor_id));
222 : 1 : c.total.fetch_add(1, std::memory_order_relaxed);
223 : 1 : break;
224 : : }
225 : 5 : case MetricEventType::kLifecycleTransition:
226 : : case MetricEventType::kMessageRejected:
227 : : case MetricEventType::kActorDrainStart:
228 : : case MetricEventType::kActorDrainComplete:
229 : : case MetricEventType::kActorDrainTimeout:
230 : : // lifecycle, rejection, and drain stubs — no aggregation yet
231 : 5 : break;
232 : : }
233 : 20 : }
234 : :
235 : : } // namespace hpactor::metrics
|