This example demonstrates the Dependency Injection (DI) pattern with common_system interfaces for loose coupling between logger and monitor systems.
#include <kcenon/common/interfaces/logger_interface.h>
#include <kcenon/common/interfaces/monitoring_interface.h>
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
#include <unordered_map>
#include <sstream>
namespace ci = kcenon::common::interfaces;
namespace {
}
class logger_interface_adapter : public ci::ILogger {
public:
explicit logger_interface_adapter(std::shared_ptr<logger>
logger)
: logger_(std::move(
logger)) {}
if (!logger_) {
return make_adapter_error("Logger not initialized");
}
return logger_->log(level, message);
}
std::string_view message,
const kcenon::common::source_location& loc) override {
if (!logger_) {
return make_adapter_error("Logger not initialized");
}
return logger_->log(level, message, loc);
}
if (!logger_) {
return make_adapter_error("Logger not initialized");
}
return logger_->log(entry);
}
bool is_enabled(ci::log_level level) const override {
return logger_ && logger_->is_enabled(level);
}
if (!logger_) {
return make_adapter_error("Logger not initialized");
}
return logger_->set_level(level);
}
ci::log_level get_level() const override {
if (!logger_) {
return ci::log_level::off;
}
return logger_->get_level();
}
if (!logger_) {
return make_adapter_error("Logger not initialized");
}
logger_->flush();
}
private:
std::shared_ptr<logger> logger_;
};
}
private:
std::unordered_map<std::string, double>
metrics_;
public:
const std::string& name,
double value) override
{
std::cout << "[Monitor] Recorded metric: " << name
<< " = " << value << std::endl;
}
const std::string& name,
double value,
const std::unordered_map<std::string, std::string>& tags) override
{
std::string tagged_name = name;
for (const auto& [key, val] : tags) {
tagged_name += "." + key + ":" + val;
}
std::cout << "[Monitor] Recorded tagged metric: " << tagged_name
<< " = " << value << std::endl;
}
ci::metrics_snapshot snapshot;
snapshot.source_id = "example_monitor";
snapshot.capture_time = std::chrono::system_clock::now();
for (
const auto& [name, value] :
metrics_) {
snapshot.add_metric(name, value);
}
}
ci::health_check_result
result;
result.timestamp = std::chrono::system_clock::now();
result.status = ci::health_status::healthy;
result.message =
"Example monitor operational";
}
std::cout << "[Monitor] Metrics reset" << std::endl;
}
}
};
std::cout << "\n=== Example 1: Basic Dependency Injection ===" << std::endl;
auto monitor = std::make_shared<example_monitor>();
if (!logger_result) {
std::cerr << "Failed to create logger: "
<< logger_result.error_message() << std::endl;
return;
}
auto logger_instance = std::shared_ptr<logger>(std::move(logger_result.value()));
logger_instance->log(ci::log_level::info, "Application started");
logger_instance->log(ci::log_level::debug, "Debug message");
logger_instance->log(ci::log_level::warning, "Warning message");
std::cout << "\nMonitor collected " << monitor->get_metric_count()
<< " metrics" << std::endl;
std::cout << "Logger health: [health_check() not yet implemented]" << std::endl;
}
std::cout << "\n=== Example 2: Optional Monitor (No Monitor) ===" << std::endl;
if (!logger_result) {
std::cerr << "Failed to create logger" << std::endl;
return;
}
auto logger_instance = std::shared_ptr<logger>(std::move(logger_result.value()));
logger_instance->log(ci::log_level::info, "Operating without monitor");
logger_instance->log(ci::log_level::warning, "Warning without monitoring");
std::cout << "Logger operates successfully without monitor (DI optional)" << std::endl;
}
std::cout << "\n=== Example 3: Runtime Monitor Injection ===" << std::endl;
if (!logger_result) {
std::cerr << "Failed to create logger" << std::endl;
return;
}
auto logger_instance = std::shared_ptr<logger>(std::move(logger_result.value()));
std::cout << "Phase 1: Operating without monitor" << std::endl;
logger_instance->log(ci::log_level::info, "Message 1 - no monitoring");
auto monitor = std::make_unique<example_monitor>();
auto* monitor_ref = monitor.get();
std::cout << "\nPhase 2: Monitor injected at runtime [set_monitor() not yet implemented]" << std::endl;
logger_instance->log(ci::log_level::info, "Message 2 - with monitoring");
logger_instance->log(ci::log_level::info, "Message 3 - with monitoring");
std::cout << "\nMonitor recorded " << monitor_ref->get_metric_count()
<< " metrics (only from Phase 2)" << std::endl;
}
std::cout << "\n=== Example 4: Monitor Swapping ===" << std::endl;
if (!logger_result) return;
auto logger_instance = std::shared_ptr<logger>(std::move(logger_result.value()));
auto monitor1 = std::make_unique<example_monitor>();
auto* monitor1_ref = monitor1.get();
std::cout << "Using Monitor 1 [set_monitor() not yet implemented]" << std::endl;
logger_instance->log(ci::log_level::info, "Message to Monitor 1");
logger_instance->log(ci::log_level::info, "Another message to Monitor 1");
size_t monitor1_metrics = monitor1_ref->get_metric_count();
auto monitor2 = std::make_unique<example_monitor>();
auto* monitor2_ref = monitor2.get();
std::cout << "\nSwapped to Monitor 2 [set_monitor() not yet implemented]" << std::endl;
logger_instance->log(ci::log_level::info, "Message to Monitor 2");
size_t monitor2_metrics = monitor2_ref->get_metric_count();
std::cout << "\nMonitor 1 metrics before swap: " << monitor1_metrics << std::endl;
std::cout << "Monitor 2 metrics after swap: " << monitor2_metrics << std::endl;
}
logger->log(ci::log_level::info, std::string(
"Used via interface - loose coupling!"));
if (
auto monitorable = std::dynamic_pointer_cast<ci::IMonitorable>(
logger)) {
auto data = monitorable->get_monitoring_data();
std::cout << "Logger provides monitoring data from "
}
}
}
std::cout << "\n=== Example 5: Interface-Based Usage ===" << std::endl;
auto monitor = std::make_shared<example_monitor>();
if (!logger_result) return;
auto logger_instance = std::shared_ptr<logger>(std::move(logger_result.value()));
auto logger_adapter = std::make_shared<logger_interface_adapter>(logger_instance);
std::cout << "Successfully used logger through interface abstraction" << std::endl;
}
std::cout << "==================================================" << std::endl;
std::cout << "Logger System - Dependency Injection Pattern Demo" << std::endl;
std::cout << "Phase 4: DI Pattern Implementation Examples" << std::endl;
std::cout << "==================================================" << std::endl;
try {
std::cout << "\n==================================================" << std::endl;
std::cout << "All DI pattern examples completed successfully!" << std::endl;
std::cout << "==================================================" << std::endl;
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
Example monitor implementation demonstrating IMonitor interface.
std::mutex metrics_mutex_
kcenon::common::Result< ci::health_check_result > check_health() override
kcenon::common::VoidResult reset() override
std::unordered_map< std::string, double > metrics_
kcenon::common::Result< ci::metrics_snapshot > get_metrics() override
size_t get_metric_count() const
kcenon::common::VoidResult record_metric(const std::string &name, double value) override
Builder pattern for logger construction with validation.
logger_builder & with_monitoring(std::shared_ptr< common::interfaces::IMonitor > monitor)
Set monitoring interface (Phase 2.2.4)
logger_builder & with_min_level(log_level level)
logger_builder & with_async(bool async=true)
result< std::unique_ptr< logger > > build()
void example_2_optional_monitor()
Example demonstrating monitor-less operation.
void example_4_monitor_swapping()
Example demonstrating monitor swapping.
void example_5_interface_based_usage()
void example_1_basic_di_pattern()
Example demonstrating DI pattern with logger and monitor.
void example_3_runtime_monitor_injection()
Example demonstrating runtime monitor injection.
void use_logger_via_interface(std::shared_ptr< ci::ILogger > logger)
Example demonstrating ILogger interface usage.
Builder pattern implementation for flexible logger configuration kcenon.
bool is_ok(const Result< T > &result)
T & get_value(Result< T > &result)