Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
alert_types.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
5#pragma once
6
16#include <algorithm>
17#include <atomic>
18#include <chrono>
19#include <cstdint>
20#include <optional>
21#include <string>
22#include <unordered_map>
23#include <variant>
24#include <vector>
25
26namespace kcenon::monitoring {
27
35enum class alert_severity : uint8_t {
36 info = 0,
37 warning,
38 critical,
40};
41
47constexpr const char* alert_severity_to_string(alert_severity severity) noexcept {
48 switch (severity) {
49 case alert_severity::info: return "info";
50 case alert_severity::warning: return "warning";
51 case alert_severity::critical: return "critical";
52 case alert_severity::emergency: return "emergency";
53 default: return "unknown";
54 }
55}
56
69enum class alert_state : uint8_t {
70 inactive = 0,
71 pending,
72 firing,
73 resolved,
75};
76
82constexpr const char* alert_state_to_string(alert_state state) noexcept {
83 switch (state) {
84 case alert_state::inactive: return "inactive";
85 case alert_state::pending: return "pending";
86 case alert_state::firing: return "firing";
87 case alert_state::resolved: return "resolved";
88 case alert_state::suppressed: return "suppressed";
89 default: return "unknown";
90 }
91}
92
101 std::unordered_map<std::string, std::string> labels;
102
103 alert_labels() = default;
104
105 explicit alert_labels(std::unordered_map<std::string, std::string> lbl)
106 : labels(std::move(lbl)) {}
107
113 void set(const std::string& key, const std::string& value) {
114 labels[key] = value;
115 }
116
122 std::string get(const std::string& key) const {
123 auto it = labels.find(key);
124 return it != labels.end() ? it->second : "";
125 }
126
132 bool has(const std::string& key) const {
133 return labels.find(key) != labels.end();
134 }
135
140 std::string fingerprint() const {
141 std::string result;
142 std::vector<std::pair<std::string, std::string>> sorted_labels(
143 labels.begin(), labels.end());
144 std::sort(sorted_labels.begin(), sorted_labels.end());
145 for (const auto& [key, value] : sorted_labels) {
146 result += key + "=" + value + ",";
147 }
148 return result;
149 }
150
151 bool operator==(const alert_labels& other) const {
152 return labels == other.labels;
153 }
154};
155
164 std::string summary;
165 std::string description;
166 std::optional<std::string> runbook_url;
167 std::unordered_map<std::string, std::string> custom;
168
169 alert_annotations() = default;
170
171 alert_annotations(std::string sum, std::string desc)
172 : summary(std::move(sum)), description(std::move(desc)) {}
173};
174
185struct alert {
186 std::string name;
191 double value = 0.0;
192
193 std::chrono::steady_clock::time_point created_at;
194 std::chrono::steady_clock::time_point updated_at;
195 std::optional<std::chrono::steady_clock::time_point> started_at;
196 std::optional<std::chrono::steady_clock::time_point> resolved_at;
197
198 uint64_t id = 0;
199 std::string rule_name;
200 std::string group_key;
201
206 : created_at(std::chrono::steady_clock::now())
208 , id(generate_id()) {}
209
215 alert(std::string alert_name, alert_labels lbl)
216 : name(std::move(alert_name))
217 , labels(std::move(lbl))
218 , created_at(std::chrono::steady_clock::now())
220 , id(generate_id()) {}
221
226 std::string fingerprint() const {
227 return name + "{" + labels.fingerprint() + "}";
228 }
229
234 bool is_active() const {
236 }
237
242 std::chrono::steady_clock::duration state_duration() const {
243 return std::chrono::steady_clock::now() - updated_at;
244 }
245
250 std::chrono::steady_clock::duration firing_duration() const {
251 if (state == alert_state::firing && started_at.has_value()) {
252 return std::chrono::steady_clock::now() - *started_at;
253 }
254 return std::chrono::steady_clock::duration::zero();
255 }
256
262 bool transition_to(alert_state new_state) {
263 if (!is_valid_transition(state, new_state)) {
264 return false;
265 }
266
267 auto now = std::chrono::steady_clock::now();
268 state = new_state;
269 updated_at = now;
270
271 if (new_state == alert_state::firing && !started_at.has_value()) {
272 started_at = now;
273 } else if (new_state == alert_state::resolved) {
274 resolved_at = now;
275 }
276
277 return true;
278 }
279
280private:
281 static uint64_t generate_id() {
282 static std::atomic<uint64_t> counter{0};
283 return counter.fetch_add(1, std::memory_order_relaxed);
284 }
285
290 // All transitions are valid from suppressed (when silence expires)
291 if (from == alert_state::suppressed) {
292 return true;
293 }
294
295 // Transition to suppressed is always valid
296 if (to == alert_state::suppressed) {
297 return true;
298 }
299
300 switch (from) {
302 return to == alert_state::pending;
304 return to == alert_state::firing || to == alert_state::inactive;
306 return to == alert_state::resolved;
308 return to == alert_state::pending || to == alert_state::inactive;
309 default:
310 return false;
311 }
312 }
313};
314
323 std::string group_key;
324 std::vector<alert> alerts;
325 std::chrono::steady_clock::time_point created_at;
326 std::chrono::steady_clock::time_point updated_at;
328
330 : created_at(std::chrono::steady_clock::now())
332
333 explicit alert_group(std::string key)
334 : group_key(std::move(key))
335 , created_at(std::chrono::steady_clock::now())
337
342 void add_alert(alert a) {
343 alerts.push_back(std::move(a));
344 updated_at = std::chrono::steady_clock::now();
345 }
346
351 size_t size() const {
352 return alerts.size();
353 }
354
359 bool empty() const {
360 return alerts.empty();
361 }
362
369 for (const auto& a : alerts) {
370 if (static_cast<uint8_t>(a.severity) > static_cast<uint8_t>(max_sev)) {
371 max_sev = a.severity;
372 }
373 }
374 return max_sev;
375 }
376};
377
386 uint64_t id = 0;
387 std::string comment;
388 std::string created_by;
390 std::chrono::steady_clock::time_point starts_at;
391 std::chrono::steady_clock::time_point ends_at;
392
394 : id(generate_id())
395 , starts_at(std::chrono::steady_clock::now())
396 , ends_at(starts_at + std::chrono::hours(1)) {}
397
402 bool is_active() const {
403 auto now = std::chrono::steady_clock::now();
404 return now >= starts_at && now < ends_at;
405 }
406
412 bool matches(const alert& a) const {
413 if (!is_active()) {
414 return false;
415 }
416
417 // All matcher labels must be present in alert labels
418 for (const auto& [key, value] : matchers.labels) {
419 if (a.labels.get(key) != value) {
420 return false;
421 }
422 }
423 return true;
424 }
425
426private:
427 static uint64_t generate_id() {
428 static std::atomic<uint64_t> counter{0};
429 return counter.fetch_add(1, std::memory_order_relaxed);
430 }
431};
432
433} // namespace kcenon::monitoring
@ counter
Monotonically increasing counter.
alert_severity
Severity levels for alerts.
Definition alert_types.h:35
@ warning
Warning condition, may require attention.
@ critical
Critical condition, immediate attention required.
@ emergency
Emergency condition, system-wide impact.
@ info
Informational, no action required.
constexpr const char * alert_state_to_string(alert_state state) noexcept
Convert alert state to string.
Definition alert_types.h:82
constexpr const char * alert_severity_to_string(alert_severity severity) noexcept
Convert alert severity to string.
Definition alert_types.h:47
alert_state
State machine states for alert lifecycle.
Definition alert_types.h:69
@ inactive
Alert condition not met.
@ suppressed
Alert is silenced.
@ pending
Condition met, waiting for duration threshold.
@ firing
Alert is active and notifications sent.
@ resolved
Alert condition cleared.
Additional metadata for alert context.
std::string description
Detailed description.
std::unordered_map< std::string, std::string > custom
Custom annotations.
alert_annotations(std::string sum, std::string desc)
std::string summary
Brief description.
std::optional< std::string > runbook_url
Link to runbook.
Group of related alerts for batch notification.
std::string group_key
Common grouping key.
alert_labels common_labels
Labels shared by all alerts.
bool empty() const
Check if group is empty.
void add_alert(alert a)
Add an alert to the group.
std::vector< alert > alerts
Alerts in this group.
size_t size() const
Get count of alerts in the group.
std::chrono::steady_clock::time_point created_at
Group creation time.
std::chrono::steady_clock::time_point updated_at
Last modification time.
alert_severity max_severity() const
Get highest severity in the group.
Key-value labels for alert identification and routing.
bool operator==(const alert_labels &other) const
std::string fingerprint() const
Generate a fingerprint for deduplication.
alert_labels(std::unordered_map< std::string, std::string > lbl)
std::unordered_map< std::string, std::string > labels
void set(const std::string &key, const std::string &value)
Add or update a label.
bool has(const std::string &key) const
Check if a label exists.
std::string get(const std::string &key) const
Get a label value.
Silence configuration to suppress alerts.
bool is_active() const
Check if silence is currently active.
std::chrono::steady_clock::time_point ends_at
Silence end time.
alert_labels matchers
Labels to match.
std::string comment
Reason for silence.
std::chrono::steady_clock::time_point starts_at
Silence start time.
std::string created_by
Creator identifier.
bool matches(const alert &a) const
Check if an alert matches this silence.
Core alert data structure.
alert_state state
Current state.
static bool is_valid_transition(alert_state from, alert_state to)
Check if state transition is valid.
std::optional< std::chrono::steady_clock::time_point > started_at
When firing started.
std::chrono::steady_clock::time_point created_at
When alert was created.
alert()
Default constructor.
double value
Current metric value.
std::optional< std::chrono::steady_clock::time_point > resolved_at
When resolved.
alert(std::string alert_name, alert_labels lbl)
Construct with name and labels.
alert_severity severity
Alert severity level.
std::chrono::steady_clock::time_point updated_at
Last state change.
std::string rule_name
Name of triggering rule.
std::chrono::steady_clock::duration state_duration() const
Get duration in current state.
static uint64_t generate_id()
uint64_t id
Unique alert ID.
std::string group_key
Grouping key for dedup.
bool transition_to(alert_state new_state)
Transition to a new state.
std::string name
Alert name/identifier.
bool is_active() const
Check if alert is currently active (pending or firing)
alert_labels labels
Identifying labels.
alert_annotations annotations
Descriptive annotations.
std::chrono::steady_clock::duration firing_duration() const
Get firing duration (if currently firing)
std::string fingerprint() const
Get alert fingerprint for deduplication.