Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
monitoring_integration_example.cpp

Demonstrates integration between logger_system and monitoring_system using only common_system interfaces (no circular dependencies).

// BSD 3-Clause License
// Copyright (c) 2021-2025, šŸ€ā˜€šŸŒ•šŸŒ„ 🌊
// See the LICENSE file in the project root for full license information.
#include <kcenon/common/interfaces/logger_interface.h>
#include <kcenon/common/interfaces/monitoring_interface.h>
#include <iostream>
#include <memory>
#include <vector>
#include <thread>
#include <chrono>
#include <iomanip>
#include <mutex>
#include <unordered_map>
using namespace kcenon::logger;
namespace ci = kcenon::common::interfaces;
class aggregating_monitor : public ci::IMonitor,
public ci::IMonitorProvider,
public std::enable_shared_from_this<aggregating_monitor> {
private:
std::vector<std::shared_ptr<ci::IMonitorable>> monitored_components_;
std::unordered_map<std::string, double> aggregated_metrics_;
mutable std::mutex mutex_;
public:
void register_component(std::shared_ptr<ci::IMonitorable> component) {
std::lock_guard<std::mutex> lock(mutex_);
monitored_components_.push_back(component);
std::cout << "[AggregatingMonitor] Registered component: "
<< component->get_component_name() << std::endl;
}
const std::string& name,
double value) override
{
std::lock_guard<std::mutex> lock(mutex_);
aggregated_metrics_[name] = value;
}
const std::string& name,
double value,
const std::unordered_map<std::string, std::string>& tags) override
{
std::string tagged_name = name;
for (const auto& [k, v] : tags) {
tagged_name += "." + k + ":" + v;
}
return record_metric(tagged_name, value);
}
std::lock_guard<std::mutex> lock(mutex_);
ci::metrics_snapshot snapshot;
snapshot.source_id = "aggregating_monitor";
snapshot.capture_time = std::chrono::system_clock::now();
// Add own metrics
for (const auto& [name, value] : aggregated_metrics_) {
snapshot.add_metric(name, value);
}
// Collect metrics from all registered components
for (const auto& component : monitored_components_) {
auto comp_data = component->get_monitoring_data();
if (kcenon::common::is_ok(comp_data)) {
const auto& component_metrics = kcenon::common::get_value(comp_data);
for (const auto& metric : component_metrics.metrics) {
snapshot.metrics.push_back(metric);
}
} else {
snapshot.add_metric("component_error_" + component->get_component_name(), 1.0);
}
}
}
std::lock_guard<std::mutex> lock(mutex_);
ci::health_check_result result;
result.timestamp = std::chrono::system_clock::now();
result.status = ci::health_status::healthy;
result.message = "Aggregating monitor operational";
// Check health of all components
for (const auto& component : monitored_components_) {
auto comp_health = component->health_check();
const auto component_name = component->get_component_name();
if (kcenon::common::is_ok(comp_health)) {
const auto& component_result = kcenon::common::get_value(comp_health);
result.metadata["component_status:" + component_name] = ci::to_string(component_result.status);
if (component_result.status == ci::health_status::unhealthy) {
result.status = ci::health_status::unhealthy;
result.message = "One or more components unhealthy";
} else if (component_result.status == ci::health_status::degraded &&
result.status == ci::health_status::healthy) {
result.status = ci::health_status::degraded;
result.message = "One or more components degraded";
}
} else {
const auto& error = kcenon::common::get_error(comp_health);
result.metadata["component_status:" + component_name] = "error:" + error.message;
if (result.status == ci::health_status::healthy) {
result.status = ci::health_status::degraded;
result.message = "Component health check failed";
}
}
}
}
std::lock_guard<std::mutex> lock(mutex_);
}
// IMonitorProvider implementation
std::shared_ptr<ci::IMonitor> get_monitor() override {
return shared_from_this();
}
std::shared_ptr<ci::IMonitor> create_monitor(const std::string& name) override {
// For this example, return self
return shared_from_this();
}
size_t get_component_count() const {
std::lock_guard<std::mutex> lock(mutex_);
return monitored_components_.size();
}
};
void print_metrics_snapshot(const ci::metrics_snapshot& snapshot) {
std::cout << "\n--- Metrics Snapshot ---" << std::endl;
std::cout << "Source: " << snapshot.source_id << std::endl;
std::cout << "Captured at: "
<< std::chrono::system_clock::to_time_t(snapshot.capture_time)
<< std::endl;
std::cout << "Metrics:" << std::endl;
for (const auto& metric : snapshot.metrics) {
std::cout << " " << std::setw(30) << std::left << metric.name
<< ": " << metric.value << std::endl;
}
}
void print_health_result(const ci::health_check_result& health) {
std::cout << "\n--- Health Check ---" << std::endl;
std::cout << "Status: " << ci::to_string(health.status) << std::endl;
std::cout << "Message: " << health.message << std::endl;
if (!health.metadata.empty()) {
std::cout << "Component Status:" << std::endl;
for (const auto& [key, value] : health.metadata) {
if (key.rfind("component_status:", 0) == 0) {
std::cout << " - " << key.substr(std::string("component_status:").size())
<< ": " << value << std::endl;
}
}
}
std::cout << "Check duration: "
<< health.check_duration.count() << "ms" << std::endl;
}
std::cout << "\n=== Example 1: Basic Monitor Integration ===" << std::endl;
auto monitor = std::make_shared<aggregating_monitor>();
auto logger_result = logger_builder()
.with_async(false)
.with_monitoring(monitor)
.build();
if (!logger_result) {
std::cerr << "Failed to create logger" << std::endl;
return;
}
auto logger_instance = std::shared_ptr<logger>(std::move(logger_result.value()));
// Register logger as monitored component
// TODO: Implement IMonitorable interface on logger class (Phase 2.2)
// Currently logger doesn't inherit from IMonitorable
// monitor->register_component(std::static_pointer_cast<ci::IMonitorable>(logger_instance));
std::cout << "[Note: logger IMonitorable integration pending Phase 2.2]" << std::endl;
// Perform logging operations
for (int i = 0; i < 5; ++i) {
logger_instance->log(ci::log_level::info,
"Log message " + std::to_string(i + 1));
}
// Get aggregated metrics
auto metrics = monitor->get_metrics();
if (kcenon::common::is_ok(metrics)) {
}
// Check aggregated health
auto health = monitor->check_health();
if (kcenon::common::is_ok(health)) {
}
}
std::cout << "\n=== Example 2: Multiple Loggers, Single Monitor ===" << std::endl;
auto monitor = std::make_shared<aggregating_monitor>();
// Create multiple logger instances
auto logger1_result = logger_builder()
.with_async(false)
.with_monitoring(monitor)
.build();
auto logger2_result = logger_builder()
.with_async(false)
.with_monitoring(monitor)
.build();
if (!logger1_result || !logger2_result) {
std::cerr << "Failed to create loggers" << std::endl;
return;
}
auto logger1 = std::shared_ptr<logger>(std::move(logger1_result.value()));
auto logger2 = std::shared_ptr<logger>(std::move(logger2_result.value()));
// Register both loggers
// TODO: Implement IMonitorable interface on logger class (Phase 2.2)
// monitor->register_component(std::static_pointer_cast<ci::IMonitorable>(logger1));
// monitor->register_component(std::static_pointer_cast<ci::IMonitorable>(logger2));
std::cout << "[Note: logger IMonitorable integration pending Phase 2.2]" << std::endl;
// Both loggers use the same monitor
logger1->log(ci::log_level::info, std::string("Message from logger 1"));
logger2->log(ci::log_level::warning, std::string("Message from logger 2"));
logger1->log(ci::log_level::error, std::string("Error from logger 1"));
std::cout << "\nMonitor tracks " << monitor->get_component_count()
<< " components" << std::endl;
// Get combined metrics
auto metrics = monitor->get_metrics();
if (kcenon::common::is_ok(metrics)) {
std::cout << "Combined metrics from all loggers:" << std::endl;
}
}
std::cout << "\n=== Example 3: IMonitorable Interface ===" << std::endl;
auto monitor = std::make_shared<aggregating_monitor>();
auto logger_result = logger_builder()
.with_async(false)
.with_monitoring(monitor)
.build();
if (!logger_result) return;
auto logger_instance = std::shared_ptr<logger>(std::move(logger_result.value()));
// Cast to IMonitorable to demonstrate interface usage
if (auto monitorable = std::dynamic_pointer_cast<ci::IMonitorable>(logger_instance)) {
std::cout << "Logger component name: "
<< monitorable->get_component_name() << std::endl;
// Perform operations
logger_instance->log(ci::log_level::info, std::string("Test message 1"));
logger_instance->log(ci::log_level::info, std::string("Test message 2"));
// Get monitoring data directly from logger
auto data = monitorable->get_monitoring_data();
if (kcenon::common::is_ok(data)) {
std::cout << "\nDirect monitoring data from logger:" << std::endl;
}
// Health check directly from logger
auto health = monitorable->health_check();
if (kcenon::common::is_ok(health)) {
std::cout << "\nDirect health check from logger:" << std::endl;
}
}
}
std::cout << "\n=== Example 4: Monitoring System Integration Simulation ===" << std::endl;
std::cout << "Note: This demonstrates how logger_system and monitoring_system" << std::endl;
std::cout << " interact via interfaces without circular dependencies" << std::endl;
// Simulate monitoring_system providing a monitor
std::shared_ptr<ci::IMonitor> monitor = std::make_shared<aggregating_monitor>();
// Logger receives monitor through DI
auto logger_result = logger_builder()
.with_async(true) // Async mode for realistic scenario
.with_monitoring(monitor)
.build();
if (!logger_result) return;
auto logger_instance = std::shared_ptr<logger>(std::move(logger_result.value()));
std::cout << "\nPhase 1: Logger operates and reports to monitor" << std::endl;
// Simulate application activity
for (int i = 0; i < 10; ++i) {
logger_instance->log(ci::log_level::info,
"Application event " + std::to_string(i + 1));
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// Give async logger time to flush
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "\nPhase 2: Monitoring system queries metrics" << std::endl;
// Monitoring system can query the monitor
auto metrics = monitor->get_metrics();
if (kcenon::common::is_ok(metrics)) {
std::cout << "Monitoring system received metrics:" << std::endl;
}
// Monitoring system can check logger health through IMonitorable
if (auto monitorable = std::dynamic_pointer_cast<ci::IMonitorable>(logger_instance)) {
auto health = monitorable->health_check();
if (kcenon::common::is_ok(health)) {
std::cout << "\nLogger health status:" << std::endl;
}
}
std::cout << "\nāœ“ Integration successful without circular dependencies" << std::endl;
}
int main() {
std::cout << "============================================================" << std::endl;
std::cout << "Logger-Monitor Integration Examples (Phase 4)" << std::endl;
std::cout << "Demonstrating loose coupling via common_system interfaces" << std::endl;
std::cout << "============================================================" << std::endl;
try {
std::cout << "\n============================================================" << std::endl;
std::cout << "All integration 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;
}
int main()
Aggregating monitor that collects metrics from multiple sources.
kcenon::common::VoidResult reset() override
std::shared_ptr< ci::IMonitor > create_monitor(const std::string &name) override
kcenon::common::Result< ci::health_check_result > check_health() override
kcenon::common::VoidResult record_metric(const std::string &name, double value) override
std::vector< std::shared_ptr< ci::IMonitorable > > monitored_components_
std::shared_ptr< ci::IMonitor > get_monitor() override
void register_component(std::shared_ptr< ci::IMonitorable > component)
std::unordered_map< std::string, double > aggregated_metrics_
kcenon::common::Result< ci::metrics_snapshot > get_metrics() 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_async(bool async=true)
result< std::unique_ptr< logger > > build()
Builder pattern implementation for flexible logger configuration kcenon.
void example_3_imonitorable_interface()
Example 3: Demonstrating IMonitorable interface.
void example_2_multiple_loggers()
Example 2: Multiple loggers with single monitor.
void example_1_basic_integration()
Example 1: Basic monitor integration with logger.
void print_health_result(const ci::health_check_result &health)
Print health check result.
void print_metrics_snapshot(const ci::metrics_snapshot &snapshot)
Print metrics snapshot in formatted way.
void example_4_monitoring_system_simulation()
Example 4: Simulating monitoring_system integration.
bool is_ok(const Result< T > &result)
VoidResult ok()
T & get_value(Result< T > &result)
error_info & get_error(Result< T > &result)
@ size
Rotate based on file size only.