Demonstrates how logger_system and monitoring_system can integrate through dependency injection WITHOUT compile-time circular dependency.
#include <kcenon/common/interfaces/logger_interface.h>
#include <kcenon/common/interfaces/monitoring_interface.h>
#include <iostream>
#include <memory>
#include <chrono>
#include <thread>
using namespace common::interfaces;
private:
public:
common::VoidResult
log(log_level level,
const std::string& message)
override {
return std::monostate{};
}
auto now = std::chrono::system_clock::now();
auto time_t = std::chrono::system_clock::to_time_t(now);
std::tm tm{};
#ifdef _MSC_VER
localtime_s(&tm, &time_t);
#else
localtime_r(&time_t, &tm);
#endif
std::cout << "[" << std::put_time(&tm, "%Y-%m-%d %H:%M:%S") << "] "
<< message << std::endl;
}
return std::monostate{};
}
common::VoidResult
log(log_level level,
const std::string& message,
const std::string& file, int line,
const std::string& function) override {
std::string detailed_message = message + " [" + file + ":" +
std::to_string(line) + " in " + function + "]";
return log(level, detailed_message);
}
common::VoidResult
log(
const log_entry& entry)
override {
return log(entry.level, entry.message, entry.file, entry.line, entry.function);
}
}
common::VoidResult
set_level(log_level level)
override {
return std::monostate{};
}
}
common::VoidResult
flush()
override {
std::cout.flush();
return std::monostate{};
}
return snapshot;
}
common::Result<health_check_result>
health_check()
override {
result.
status = health_status::healthy;
result.
message =
"Console logger operational";
return result;
}
return "console_logger";
}
}
}
};
std::cout << "\n=== Scenario 1: Standalone Systems ===" << std::endl;
std::cout << "Both systems work independently without each other.\n" << std::endl;
auto logger = std::make_shared<console_logger>();
logger->log(log_level::info, "Logger operating standalone");
std::cout << "ā Logger works without monitor\n" << std::endl;
auto monitor = std::make_shared<performance_monitor>();
auto result = monitor->record_metric("standalone_metric", 42.0);
if (std::holds_alternative<std::monostate>(result)) {
std::cout << "ā Monitor works without logger\n" << std::endl;
}
}
std::cout << "\n=== Scenario 2: Logger with Monitor ===" << std::endl;
std::cout << "Logger receives monitor via DI for metrics collection.\n" << std::endl;
auto monitor = std::make_shared<performance_monitor>();
auto logger = std::make_shared<console_logger>();
logger->set_monitor(monitor);
logger->log(log_level::info, "First message with monitoring");
logger->log(log_level::warning, "Second message with monitoring");
logger->log(log_level::error, "Third message with monitoring");
auto metrics_result = monitor->get_metrics();
if (std::holds_alternative<metrics_snapshot>(metrics_result)) {
auto& snapshot = std::get<metrics_snapshot>(metrics_result);
std::cout << "\nā Monitor collected " << snapshot.metrics.size()
<< " metrics from logger" << std::endl;
for (
const auto&
metric : snapshot.metrics) {
}
}
}
std::cout << "\n\n=== Scenario 3: Monitor with Logger ===" << std::endl;
std::cout << "Monitor can report to logger (via adapter pattern).\n" << std::endl;
auto logger = std::make_shared<console_logger>();
auto monitor = std::make_shared<performance_monitor>();
monitor->record_metric("cpu_usage", 45.5);
monitor->record_metric("memory_usage", 512.0);
auto health_result = monitor->check_health();
if (std::holds_alternative<health_check_result>(health_result)) {
auto& health = std::get<health_check_result>(health_result);
std::string health_msg =
"Monitor health: " +
to_string(health.status);
logger->log(log_level::info, health_msg);
}
std::cout << "\nā Monitor can report status to logger" << std::endl;
}
std::cout << "\n\n=== Scenario 4: Bidirectional DI (No Circular Dependency!) ===" << std::endl;
std::cout << "Both systems integrated at RUNTIME without compile-time circular dependency.\n" << std::endl;
auto logger = std::make_shared<console_logger>();
auto monitor = std::make_shared<performance_monitor>();
logger->set_monitor(monitor);
std::cout << "\nā Bidirectional dependency injection complete" << std::endl;
std::cout << " Logger -> uses Monitor for metrics" << std::endl;
std::cout << " Monitor <- logs status via Logger\n" << std::endl;
std::cout << "\nSimulating application workload..." << std::endl;
for (int i = 0; i < 10; ++i) {
logger->log(log_level::info, "Processing request " + std::to_string(i));
monitor->record_metric("requests_processed", i + 1);
monitor->record_metric("response_time_ms", 50.0 + (i * 5));
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
std::cout << "\n=== System Health Check ===" << std::endl;
auto logger_health = logger->health_check();
if (std::holds_alternative<health_check_result>(logger_health)) {
auto& health = std::get<health_check_result>(logger_health);
std::cout <<
"Logger Status: " <<
to_string(health.status)
<< " - " << health.message << std::endl;
std::cout << " Messages logged: " << logger->get_message_count() << std::endl;
}
auto monitor_health = monitor->check_health();
if (std::holds_alternative<health_check_result>(monitor_health)) {
auto& health = std::get<health_check_result>(monitor_health);
std::cout <<
"Monitor Status: " <<
to_string(health.status)
<< " - " << health.message << std::endl;
}
std::cout << "\n=== Collected Metrics ===" << std::endl;
auto logger_metrics = logger->get_monitoring_data();
if (std::holds_alternative<metrics_snapshot>(logger_metrics)) {
auto& snapshot = std::get<metrics_snapshot>(logger_metrics);
std::cout << "Logger Metrics:" << std::endl;
for (
const auto&
metric : snapshot.metrics) {
}
}
auto monitor_metrics = monitor->get_metrics();
if (std::holds_alternative<metrics_snapshot>(monitor_metrics)) {
auto& snapshot = std::get<metrics_snapshot>(monitor_metrics);
std::cout << "\nMonitor Metrics:" << std::endl;
for (
const auto&
metric : snapshot.metrics) {
}
}
std::cout << "\nā Both systems fully operational and integrated!" << std::endl;
}
std::cout << "\n\n=== Scenario 5: Runtime Flexibility ===" << std::endl;
std::cout << "Dependencies can be changed at runtime.\n" << std::endl;
auto logger = std::make_shared<console_logger>();
auto monitor1 = std::make_shared<performance_monitor>();
auto monitor2 = std::make_shared<performance_monitor>();
logger->set_monitor(monitor1);
logger->log(log_level::info, "Using monitor 1");
logger->set_monitor(monitor2);
logger->log(log_level::info, "Switched to monitor 2");
logger->set_monitor(nullptr);
logger->log(log_level::info, "Operating without monitor");
std::cout << "\nā Runtime dependency changes work seamlessly" << std::endl;
}
std::cout << "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā" << std::endl;
std::cout << "ā Phase 4: Bidirectional DI Example ā" << std::endl;
std::cout << "ā Demonstrating Circular Dependency Resolution ā" << std::endl;
std::cout << "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā" << std::endl;
try {
std::cout << "\n\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā" << std::endl;
std::cout << "ā ā ALL SCENARIOS PASSED ā" << std::endl;
std::cout << "ā ā" << std::endl;
std::cout << "ā Key Achievement: ā" << std::endl;
std::cout << "ā ⢠NO compile-time circular dependency ā" << std::endl;
std::cout << "ā ⢠Runtime bidirectional integration works ā" << std::endl;
std::cout << "ā ⢠Both systems can operate standalone ā" << std::endl;
std::cout << "ā ⢠Pure interface-based design ā" << std::endl;
std::cout << "āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā" << std::endl;
return 0;
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
}
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::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)
int get_message_count() const
auto to_string(plugin_load_error error) -> std::string
Convert plugin_load_error to string.
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.