Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
bidirectional_di_example.cpp
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
21#include <kcenon/common/interfaces/logger_interface.h>
22#include <kcenon/common/interfaces/monitoring_interface.h>
23#include <iostream>
24#include <memory>
25#include <chrono>
26#include <thread>
27
28using namespace kcenon::monitoring;
29using namespace common::interfaces;
30
37class console_logger : public ILogger, public IMonitorable {
38private:
39 std::atomic<int> message_count_{0};
40 log_level min_level_{log_level::info};
41 std::shared_ptr<IMonitor> monitor_;
42
43public:
44 common::VoidResult log(log_level level, const std::string& message) override {
45 if (level < min_level_) {
46 return std::monostate{};
47 }
48
50
51 auto now = std::chrono::system_clock::now();
52 auto time_t = std::chrono::system_clock::to_time_t(now);
53 std::tm tm{};
54#ifdef _MSC_VER
55 localtime_s(&tm, &time_t);
56#else
57 localtime_r(&time_t, &tm);
58#endif
59
60 std::cout << "[" << std::put_time(&tm, "%Y-%m-%d %H:%M:%S") << "] "
61 << "[" << to_string(level) << "] "
62 << message << std::endl;
63
64 // If monitor is injected, record logging metrics
65 if (monitor_) {
66 monitor_->record_metric("messages_logged", message_count_.load());
67 }
68
69 return std::monostate{};
70 }
71
72 common::VoidResult log(log_level level, const std::string& message,
73 const std::string& file, int line,
74 const std::string& function) override {
75 std::string detailed_message = message + " [" + file + ":" +
76 std::to_string(line) + " in " + function + "]";
77 return log(level, detailed_message);
78 }
79
80 common::VoidResult log(const log_entry& entry) override {
81 return log(entry.level, entry.message, entry.file, entry.line, entry.function);
82 }
83
84 bool is_enabled(log_level level) const override {
85 return level >= min_level_;
86 }
87
88 common::VoidResult set_level(log_level level) override {
89 min_level_ = level;
90 return std::monostate{};
91 }
92
93 log_level get_level() const override {
94 return min_level_;
95 }
96
97 common::VoidResult flush() override {
98 std::cout.flush();
99 return std::monostate{};
100 }
101
102 // IMonitorable implementation
103 common::Result<metrics_snapshot> get_monitoring_data() override {
104 metrics_snapshot snapshot;
105 snapshot.source_id = "console_logger";
106 snapshot.add_metric("total_messages", message_count_.load());
107 snapshot.add_metric("is_enabled", is_enabled(log_level::info) ? 1.0 : 0.0);
108 return snapshot;
109 }
110
111 common::Result<health_check_result> health_check() override {
112 health_check_result result;
113 result.status = health_status::healthy;
114 result.message = "Console logger operational";
115 result.metadata["message_count"] = std::to_string(message_count_.load());
116 return result;
117 }
118
119 std::string get_component_name() const override {
120 return "console_logger";
121 }
122
123 // Allow monitor injection
124 void set_monitor(std::shared_ptr<IMonitor> monitor) {
125 monitor_ = std::move(monitor);
126 }
127
128 int get_message_count() const {
129 return message_count_.load();
130 }
131};
132
137 std::cout << "\n=== Scenario 1: Standalone Systems ===" << std::endl;
138 std::cout << "Both systems work independently without each other.\n" << std::endl;
139
140 // Logger works alone
141 auto logger = std::make_shared<console_logger>();
142 logger->log(log_level::info, "Logger operating standalone");
143 std::cout << "āœ“ Logger works without monitor\n" << std::endl;
144
145 // Monitor works alone
146 auto monitor = std::make_shared<performance_monitor>();
147 auto result = monitor->record_metric("standalone_metric", 42.0);
148 if (std::holds_alternative<std::monostate>(result)) {
149 std::cout << "āœ“ Monitor works without logger\n" << std::endl;
150 }
151}
152
157 std::cout << "\n=== Scenario 2: Logger with Monitor ===" << std::endl;
158 std::cout << "Logger receives monitor via DI for metrics collection.\n" << std::endl;
159
160 auto monitor = std::make_shared<performance_monitor>();
161 auto logger = std::make_shared<console_logger>();
162
163 // Inject monitor into logger
164 logger->set_monitor(monitor);
165
166 // Log some messages
167 logger->log(log_level::info, "First message with monitoring");
168 logger->log(log_level::warning, "Second message with monitoring");
169 logger->log(log_level::error, "Third message with monitoring");
170
171 // Check monitor collected metrics
172 auto metrics_result = monitor->get_metrics();
173 if (std::holds_alternative<metrics_snapshot>(metrics_result)) {
174 auto& snapshot = std::get<metrics_snapshot>(metrics_result);
175 std::cout << "\nāœ“ Monitor collected " << snapshot.metrics.size()
176 << " metrics from logger" << std::endl;
177
178 for (const auto& metric : snapshot.metrics) {
179 std::cout << " - " << metric.name << ": " << metric.value << std::endl;
180 }
181 }
182}
183
188 std::cout << "\n\n=== Scenario 3: Monitor with Logger ===" << std::endl;
189 std::cout << "Monitor can report to logger (via adapter pattern).\n" << std::endl;
190
191 auto logger = std::make_shared<console_logger>();
192 auto monitor = std::make_shared<performance_monitor>();
193
194 // Monitor records metrics
195 monitor->record_metric("cpu_usage", 45.5);
196 monitor->record_metric("memory_usage", 512.0);
197
198 // Check health and log result
199 auto health_result = monitor->check_health();
200 if (std::holds_alternative<health_check_result>(health_result)) {
201 auto& health = std::get<health_check_result>(health_result);
202 std::string health_msg = "Monitor health: " + to_string(health.status);
203 logger->log(log_level::info, health_msg);
204 }
205
206 std::cout << "\nāœ“ Monitor can report status to logger" << std::endl;
207}
208
213 std::cout << "\n\n=== Scenario 4: Bidirectional DI (No Circular Dependency!) ===" << std::endl;
214 std::cout << "Both systems integrated at RUNTIME without compile-time circular dependency.\n" << std::endl;
215
216 // Create both systems
217 auto logger = std::make_shared<console_logger>();
218 auto monitor = std::make_shared<performance_monitor>();
219
220 // Bidirectional injection
221 logger->set_monitor(monitor);
222 // Note: In real logger_system, logger would also be injected into adapter
223
224 std::cout << "\nāœ“ Bidirectional dependency injection complete" << std::endl;
225 std::cout << " Logger -> uses Monitor for metrics" << std::endl;
226 std::cout << " Monitor <- logs status via Logger\n" << std::endl;
227
228 // Simulate application workload
229 std::cout << "\nSimulating application workload..." << std::endl;
230 for (int i = 0; i < 10; ++i) {
231 // Log activity
232 logger->log(log_level::info, "Processing request " + std::to_string(i));
233
234 // Record performance metrics
235 monitor->record_metric("requests_processed", i + 1);
236 monitor->record_metric("response_time_ms", 50.0 + (i * 5));
237
238 std::this_thread::sleep_for(std::chrono::milliseconds(10));
239 }
240
241 // Check both systems' health
242 std::cout << "\n=== System Health Check ===" << std::endl;
243
244 auto logger_health = logger->health_check();
245 if (std::holds_alternative<health_check_result>(logger_health)) {
246 auto& health = std::get<health_check_result>(logger_health);
247 std::cout << "Logger Status: " << to_string(health.status)
248 << " - " << health.message << std::endl;
249 std::cout << " Messages logged: " << logger->get_message_count() << std::endl;
250 }
251
252 auto monitor_health = monitor->check_health();
253 if (std::holds_alternative<health_check_result>(monitor_health)) {
254 auto& health = std::get<health_check_result>(monitor_health);
255 std::cout << "Monitor Status: " << to_string(health.status)
256 << " - " << health.message << std::endl;
257 }
258
259 // Get comprehensive metrics
260 std::cout << "\n=== Collected Metrics ===" << std::endl;
261
262 auto logger_metrics = logger->get_monitoring_data();
263 if (std::holds_alternative<metrics_snapshot>(logger_metrics)) {
264 auto& snapshot = std::get<metrics_snapshot>(logger_metrics);
265 std::cout << "Logger Metrics:" << std::endl;
266 for (const auto& metric : snapshot.metrics) {
267 std::cout << " " << metric.name << ": " << metric.value << std::endl;
268 }
269 }
270
271 auto monitor_metrics = monitor->get_metrics();
272 if (std::holds_alternative<metrics_snapshot>(monitor_metrics)) {
273 auto& snapshot = std::get<metrics_snapshot>(monitor_metrics);
274 std::cout << "\nMonitor Metrics:" << std::endl;
275 for (const auto& metric : snapshot.metrics) {
276 std::cout << " " << metric.name << ": " << metric.value << std::endl;
277 }
278 }
279
280 std::cout << "\nāœ“ Both systems fully operational and integrated!" << std::endl;
281}
282
287 std::cout << "\n\n=== Scenario 5: Runtime Flexibility ===" << std::endl;
288 std::cout << "Dependencies can be changed at runtime.\n" << std::endl;
289
290 auto logger = std::make_shared<console_logger>();
291 auto monitor1 = std::make_shared<performance_monitor>();
292 auto monitor2 = std::make_shared<performance_monitor>();
293
294 // Start with first monitor
295 logger->set_monitor(monitor1);
296 logger->log(log_level::info, "Using monitor 1");
297
298 // Switch to second monitor
299 logger->set_monitor(monitor2);
300 logger->log(log_level::info, "Switched to monitor 2");
301
302 // Remove monitor completely
303 logger->set_monitor(nullptr);
304 logger->log(log_level::info, "Operating without monitor");
305
306 std::cout << "\nāœ“ Runtime dependency changes work seamlessly" << std::endl;
307}
308
309int main() {
310 std::cout << "╔═══════════════════════════════════════════════════════════╗" << std::endl;
311 std::cout << "ā•‘ Phase 4: Bidirectional DI Example ā•‘" << std::endl;
312 std::cout << "ā•‘ Demonstrating Circular Dependency Resolution ā•‘" << std::endl;
313 std::cout << "ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•" << std::endl;
314
315 try {
321
322 std::cout << "\n\n╔═══════════════════════════════════════════════════════════╗" << std::endl;
323 std::cout << "ā•‘ āœ“ ALL SCENARIOS PASSED ā•‘" << std::endl;
324 std::cout << "ā•‘ ā•‘" << std::endl;
325 std::cout << "ā•‘ Key Achievement: ā•‘" << std::endl;
326 std::cout << "ā•‘ • NO compile-time circular dependency ā•‘" << std::endl;
327 std::cout << "ā•‘ • Runtime bidirectional integration works ā•‘" << std::endl;
328 std::cout << "ā•‘ • Both systems can operate standalone ā•‘" << std::endl;
329 std::cout << "ā•‘ • Pure interface-based design ā•‘" << std::endl;
330 std::cout << "ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•" << std::endl;
331
332 return 0;
333 } catch (const std::exception& e) {
334 std::cerr << "Error: " << e.what() << std::endl;
335 return 1;
336 }
337}
void demo_standalone_systems()
Scenario 1: Standalone Systems.
void demo_runtime_flexibility()
Scenario 5: Runtime Flexibility.
void demo_bidirectional_integration()
Scenario 4: Bidirectional DI (THE KEY DEMO!)
void demo_logger_with_monitor()
Scenario 2: Logger with Monitor Injection.
void demo_monitor_with_logger()
Scenario 3: Monitor with Logger Injection (via adapter)
Simple console logger implementing ILogger interface.
common::VoidResult log(log_level level, const std::string &message, const std::string &file, int line, const std::string &function) override
common::VoidResult log(const log_entry &entry) override
common::Result< health_check_result > health_check() override
bool is_enabled(log_level level) const override
std::atomic< int > message_count_
common::VoidResult log(log_level level, const std::string &message) override
common::Result< metrics_snapshot > get_monitoring_data() override
std::string get_component_name() const override
common::VoidResult set_level(log_level level) override
common::VoidResult flush() override
std::shared_ptr< IMonitor > monitor_
log_level get_level() const override
void set_monitor(std::shared_ptr< IMonitor > monitor)
auto to_string(plugin_load_error error) -> std::string
Convert plugin_load_error to string.
Performance monitoring and profiling implementation.
Result of a health check operation.
std::unordered_map< std::string, std::string > metadata
Basic metric structure for interface compatibility.
std::variant< double, int64_t, std::string > value
Complete snapshot of metrics at a point in time.
void add_metric(const std::string &name, double value)
Add a metric to the snapshot.