Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
monitorable_interface.h
Go to the documentation of this file.
1#pragma once
2
3// BSD 3-Clause License
4// Copyright (c) 2025, 🍀☀🌕🌥 🌊
5// See the LICENSE file in the project root for full license information.
6
7
17#include "../core/error_codes.h"
18#include <string>
19#include <unordered_map>
20#include <vector>
21#include <chrono>
22#include <memory>
23#include <any>
24#include <optional>
25#include <algorithm>
26
27namespace kcenon { namespace monitoring {
28
64 using metric_map = std::unordered_map<std::string, double>;
65 using tag_map = std::unordered_map<std::string, std::string>;
66
67private:
70 std::chrono::system_clock::time_point timestamp_;
71 std::string component_name_;
72
73public:
78 : timestamp_(std::chrono::system_clock::now()) {}
79
84 explicit monitoring_data(const std::string& name)
85 : timestamp_(std::chrono::system_clock::now())
86 , component_name_(name) {}
87
93 void add_metric(const std::string& key, double value) {
94 metrics_[key] = value;
95 }
96
102 void add_tag(const std::string& key, const std::string& value) {
103 tags_[key] = value;
104 }
105
111 std::optional<double> get_metric(const std::string& key) const {
112 auto it = metrics_.find(key);
113 if (it != metrics_.end()) {
114 return it->second;
115 }
116 return std::nullopt;
117 }
118
124 std::optional<std::string> get_tag(const std::string& key) const {
125 auto it = tags_.find(key);
126 if (it != tags_.end()) {
127 return it->second;
128 }
129 return std::nullopt;
130 }
131
136 const metric_map& get_metrics() const {
137 return metrics_;
138 }
139
144 const tag_map& get_tags() const {
145 return tags_;
146 }
147
152 std::chrono::system_clock::time_point get_timestamp() const {
153 return timestamp_;
154 }
155
160 const std::string& get_component_name() const {
161 return component_name_;
162 }
163
168 void set_component_name(const std::string& name) {
169 component_name_ = name;
170 }
171
175 void clear() {
176 metrics_.clear();
177 tags_.clear();
178 }
179
184 bool empty() const {
185 return metrics_.empty() && tags_.empty();
186 }
187
192 std::size_t metric_count() const {
193 return metrics_.size();
194 }
195
200 std::size_t tag_count() const {
201 return tags_.size();
202 }
203
209 void merge(const monitoring_data& other, const std::string& prefix = "") {
210 for (const auto& [key, value] : other.metrics_) {
211 if (prefix.empty()) {
212 metrics_[key] = value;
213 } else {
214 metrics_[prefix + "." + key] = value;
215 }
216 }
217
218 for (const auto& [key, value] : other.tags_) {
219 if (prefix.empty()) {
220 tags_[key] = value;
221 } else {
222 tags_[prefix + "." + key] = value;
223 }
224 }
225 }
226};
227
266public:
267 virtual ~monitorable_interface() = default;
268
273 virtual common::Result<monitoring_data> get_monitoring_data() const = 0;
274
279 virtual std::string get_monitoring_id() const = 0;
280
285 virtual bool is_monitoring_enabled() const {
286 return true;
287 }
288
294 virtual common::VoidResult set_monitoring_enabled(bool enable) {
295 // Default implementation - can be overridden
296 (void)enable; // Suppress unused parameter warning
297 return common::ok();
298 }
299
304 virtual common::VoidResult reset_monitoring() {
305 // Default implementation - can be overridden
306 return common::ok();
307 }
308};
309
344protected:
345 std::string monitoring_id_;
348
349public:
354 explicit monitorable_component(const std::string& id)
355 : monitoring_id_(id)
356 , cached_data_(id) {}
357
362 std::string get_monitoring_id() const override {
363 return monitoring_id_;
364 }
365
370 bool is_monitoring_enabled() const override {
371 return monitoring_enabled_;
372 }
373
379 common::VoidResult set_monitoring_enabled(bool enable) override {
380 monitoring_enabled_ = enable;
381 return common::ok();
382 }
383
388 common::VoidResult reset_monitoring() override {
391 return common::ok();
392 }
393
394protected:
400 void update_metric(const std::string& key, double value) const {
401 cached_data_.add_metric(key, value);
402 }
403
409 void update_tag(const std::string& key, const std::string& value) const {
410 cached_data_.add_tag(key, value);
411 }
412};
413
454private:
455 std::vector<std::shared_ptr<monitorable_interface>> components_;
456 std::string aggregator_id_;
457
458public:
463 explicit monitoring_aggregator(const std::string& id = "aggregator")
464 : aggregator_id_(id) {}
465
470 void add_component(std::shared_ptr<monitorable_interface> component) {
471 if (component) {
472 components_.push_back(component);
473 }
474 }
475
481 bool remove_component(const std::string& id) {
482 auto it = std::remove_if(components_.begin(), components_.end(),
483 [&id](const auto& comp) {
484 return comp->get_monitoring_id() == id;
485 });
486
487 if (it != components_.end()) {
488 components_.erase(it, components_.end());
489 return true;
490 }
491 return false;
492 }
493
498 common::Result<monitoring_data> collect_all() const {
500
501 for (const auto& component : components_) {
502 if (!component->is_monitoring_enabled()) {
503 continue;
504 }
505
506 auto result = component->get_monitoring_data();
507 if (result.is_ok()) {
508 aggregated.merge(result.value(), component->get_monitoring_id());
509 } else {
510 // Log error but continue with other components
511 aggregated.add_tag(
512 component->get_monitoring_id() + ".error",
513 result.error().message
514 );
515 }
516 }
517
518 // Add aggregator metadata
519 aggregated.add_metric("aggregator.component_count",
520 static_cast<double>(components_.size()));
521 aggregated.add_metric("aggregator.total_metrics",
522 static_cast<double>(aggregated.metric_count()));
523
524 return common::ok(std::move(aggregated));
525 }
526
532 std::shared_ptr<monitorable_interface> get_component(const std::string& id) const {
533 auto it = std::find_if(components_.begin(), components_.end(),
534 [&id](const auto& comp) {
535 return comp->get_monitoring_id() == id;
536 });
537
538 return (it != components_.end()) ? *it : nullptr;
539 }
540
545 std::vector<std::string> get_component_ids() const {
546 std::vector<std::string> ids;
547 ids.reserve(components_.size());
548
549 for (const auto& component : components_) {
550 ids.push_back(component->get_monitoring_id());
551 }
552
553 return ids;
554 }
555
559 void clear() {
560 components_.clear();
561 }
562
567 std::size_t size() const {
568 return components_.size();
569 }
570};
571
572} } // namespace kcenon::monitoring
Base class providing default monitorable implementation.
common::VoidResult reset_monitoring() override
Reset monitoring data.
void update_metric(const std::string &key, double value) const
Helper to update a metric.
monitorable_component(const std::string &id)
Constructor.
bool is_monitoring_enabled() const override
Check if monitoring is enabled.
void update_tag(const std::string &key, const std::string &value) const
Helper to update a tag.
std::string get_monitoring_id() const override
Get monitoring identifier.
common::VoidResult set_monitoring_enabled(bool enable) override
Enable or disable monitoring.
Interface for components that can be monitored.
virtual common::VoidResult reset_monitoring()
Reset monitoring counters and state.
virtual common::VoidResult set_monitoring_enabled(bool enable)
Enable or disable monitoring.
virtual std::string get_monitoring_id() const =0
Get the component's monitoring identifier.
virtual bool is_monitoring_enabled() const
Check if monitoring is enabled for this component.
virtual common::Result< monitoring_data > get_monitoring_data() const =0
Get current monitoring data from the component.
Utility class to aggregate metrics from multiple monitorable components.
std::size_t size() const
Get the number of registered components.
common::Result< monitoring_data > collect_all() const
Collect data from all components.
std::vector< std::shared_ptr< monitorable_interface > > components_
std::vector< std::string > get_component_ids() const
Get all component IDs.
monitoring_aggregator(const std::string &id="aggregator")
Constructor.
bool remove_component(const std::string &id)
Remove a component by ID.
std::shared_ptr< monitorable_interface > get_component(const std::string &id) const
Get a specific component by ID.
void add_component(std::shared_ptr< monitorable_interface > component)
Add a component to monitor.
Monitoring system specific error codes.
Result pattern type definitions for monitoring system.
Container for monitoring metrics from a component.
void merge(const monitoring_data &other, const std::string &prefix="")
Merge another monitoring_data into this one.
std::size_t metric_count() const
Get the number of metrics.
bool empty() const
Check if data is empty.
monitoring_data(const std::string &name)
Constructor with component name.
std::chrono::system_clock::time_point get_timestamp() const
Get the timestamp.
std::optional< std::string > get_tag(const std::string &key) const
Get a tag value.
void set_component_name(const std::string &name)
Set the component name.
std::size_t tag_count() const
Get the number of tags.
std::unordered_map< std::string, std::string > tag_map
std::chrono::system_clock::time_point timestamp_
void clear()
Clear all metrics and tags.
std::optional< double > get_metric(const std::string &key) const
Get a metric value.
const std::string & get_component_name() const
Get the component name.
const tag_map & get_tags() const
Get all tags.
const metric_map & get_metrics() const
Get all metrics.
void add_metric(const std::string &key, double value)
Add a numeric metric.
std::unordered_map< std::string, double > metric_map
void add_tag(const std::string &key, const std::string &value)
Add a tag (string metadata)