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

This file demonstrates how the adapter pattern would replace conditional compilation in logger_system. This is NOT production code, but a conceptual example to validate the approach.

Note
Since Issue #225, thread_system is OPTIONAL and logger_system uses standalone mode by default. This POC illustrates the architectural pattern that enables this flexibility.

Compile: clang++ -std=c++20 -I../include adapter_pattern_poc.cpp

// BSD 3-Clause License
// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
// See the LICENSE file in the project root for full license information.
#include <iostream>
#include <memory>
#include <string>
#include <chrono>
// =============================================================================
// BEFORE: Conditional Compilation Approach (Current)
// =============================================================================
#ifdef USE_EXAMPLE_MODE
#include "external_interface.h" // Different header based on mode
class logger_old : public external_interface { // Different base class
public:
void log(const std::string& message) {
#ifdef MODE_A
std::cout << "[Mode A] " << message << std::endl;
#elif MODE_B
std::cout << "[Mode B] " << message << std::endl;
#else
std::cout << "[Default] " << message << std::endl;
#endif
}
};
#else
class logger_old { // No base class in standalone mode
public:
void log(const std::string& message) {
std::cout << "[Standalone] " << message << std::endl;
}
};
#endif
// Problems with above approach:
// 1. Must recompile for each mode
// 2. Cannot test all modes with single binary
// 3. Control flow obscured by preprocessor
// =============================================================================
// AFTER: Adapter Pattern Approach (Proposed)
// =============================================================================
// Step 1: Pure core implementation (no external dependencies)
class logger_core {
public:
void log_internal(const std::string& message) {
// Pure logging logic - same for all modes
timestamp_ = std::chrono::system_clock::now();
messages_.push_back(message);
// Simulate logging work
std::cout << "[CORE] " << message << std::endl;
}
size_t message_count() const {
return messages_.size();
}
private:
std::vector<std::string> messages_;
std::chrono::system_clock::time_point timestamp_;
};
// Step 2: Adapter base class
public:
explicit logger_adapter(std::shared_ptr<logger_core> core)
: core_(std::move(core)) {}
virtual ~logger_adapter() = default;
// Delegate to core
void log(const std::string& message) {
core_->log_internal(message);
}
size_t message_count() const {
return core_->message_count();
}
protected:
std::shared_ptr<logger_core> core_;
};
// Step 3: Specialized adapters for each integration mode
// Standalone adapter - minimal overhead
public:
void log_standalone(const std::string& message) {
std::cout << "[Standalone Mode] ";
log(message);
}
};
// External interface simulation
public:
virtual ~external_system_interface() = default;
virtual void external_log(const std::string& message) = 0;
virtual std::string get_interface_name() const = 0;
};
// Thread system adapter
: public logger_adapter
, public external_system_interface { // Multiple inheritance OK
public:
// Implement external_system_interface
void external_log(const std::string& message) override {
std::cout << "[Thread System Integration] ";
log(message);
}
std::string get_interface_name() const override {
return "thread_system::logger_interface";
}
};
// Common system adapter (different interface)
public:
virtual ~common_system_interface() = default;
virtual void monitored_log(const std::string& message) = 0;
virtual size_t get_metric_count() const = 0;
};
: public logger_adapter
public:
void monitored_log(const std::string& message) override {
std::cout << "[Common System Integration] ";
log(message);
}
size_t get_metric_count() const override {
return metric_count_;
}
private:
size_t metric_count_ = 0;
};
// Full integration adapter (both interfaces)
: public logger_adapter
public:
void external_log(const std::string& message) override {
std::cout << "[Full Integration - External] ";
log(message);
}
std::string get_interface_name() const override {
return "full_integration";
}
void monitored_log(const std::string& message) override {
std::cout << "[Full Integration - Monitored] ";
log(message);
}
size_t get_metric_count() const override {
return message_count();
}
};
// Step 4: Factory for runtime selection
enum class integration_mode {
};
public:
static std::unique_ptr<logger_adapter> create(integration_mode mode) {
auto core = std::make_shared<logger_core>();
switch (mode) {
return std::make_unique<standalone_adapter>(core);
return std::make_unique<thread_system_adapter>(core);
return std::make_unique<common_system_adapter>(core);
return std::make_unique<full_integration_adapter>(core);
default:
throw std::invalid_argument("Unknown integration mode");
}
}
};
// =============================================================================
// Demonstration
// =============================================================================
std::cout << "\n=== Adapter Pattern Proof of Concept ===\n" << std::endl;
// Test 1: Standalone mode
{
std::cout << "Test 1: Standalone Mode" << std::endl;
logger->log("Hello from standalone mode");
std::cout << "Messages logged: " << logger->message_count() << "\n" << std::endl;
}
// Test 2: Thread system integration
{
std::cout << "Test 2: Thread System Integration" << std::endl;
// Can use as logger_adapter
logger->log("Hello as adapter");
// Can cast to external interface
auto* external = dynamic_cast<external_system_interface*>(logger.get());
if (external) {
external->external_log("Hello via external interface");
std::cout << "Interface: " << external->get_interface_name() << std::endl;
}
std::cout << std::endl;
}
// Test 3: Common system integration
{
std::cout << "Test 3: Common System Integration" << std::endl;
auto* monitored = dynamic_cast<common_system_interface*>(logger.get());
if (monitored) {
monitored->monitored_log("Message 1");
monitored->monitored_log("Message 2");
std::cout << "Metrics collected: " << monitored->get_metric_count() << std::endl;
}
std::cout << std::endl;
}
// Test 4: Full integration (both interfaces)
{
std::cout << "Test 4: Full Integration" << std::endl;
// Use both interfaces
auto* external = dynamic_cast<external_system_interface*>(logger.get());
auto* monitored = dynamic_cast<common_system_interface*>(logger.get());
if (external && monitored) {
external->external_log("Via external interface");
monitored->monitored_log("Via monitoring interface");
std::cout << "Total messages: " << monitored->get_metric_count() << std::endl;
}
std::cout << std::endl;
}
// Test 5: Runtime mode switching (same binary!)
{
std::cout << "Test 5: Runtime Mode Switching" << std::endl;
std::cout << "All modes tested with SINGLE BINARY" << std::endl;
std::cout << "No recompilation needed!" << std::endl;
}
}
// Performance comparison
std::cout << "\n=== Performance Comparison ===\n" << std::endl;
const int iterations = 1000000;
auto core = std::make_shared<logger_core>();
// Direct call (no virtual)
{
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < iterations; ++i) {
core->log_internal("test");
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
std::cout << "Direct call: " << duration.count() / iterations << " ns/call" << std::endl;
}
// Virtual call through adapter
{
auto adapter = std::make_unique<standalone_adapter>(core);
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < iterations; ++i) {
adapter->log("test");
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
std::cout << "Virtual call: " << duration.count() / iterations << " ns/call" << std::endl;
std::cout << "Overhead: ~1-2ns (negligible for I/O operations)" << std::endl;
}
}
int main() {
std::cout << "\n=== Benefits Summary ===" << std::endl;
std::cout << "✅ Single binary for all modes" << std::endl;
std::cout << "✅ Runtime mode selection" << std::endl;
std::cout << "✅ Easier testing (no recompilation)" << std::endl;
std::cout << "✅ Clear code structure" << std::endl;
std::cout << "✅ Minimal performance overhead" << std::endl;
std::cout << "✅ Better maintainability" << std::endl;
return 0;
}
void benchmark_overhead()
int main()
void demonstrate_adapters()
void monitored_log(const std::string &message) override
size_t get_metric_count() const override
virtual ~common_system_interface()=default
virtual size_t get_metric_count() const =0
virtual void monitored_log(const std::string &message)=0
virtual std::string get_interface_name() const =0
virtual void external_log(const std::string &message)=0
virtual ~external_system_interface()=default
void external_log(const std::string &message) override
size_t get_metric_count() const override
void monitored_log(const std::string &message) override
std::string get_interface_name() const override
virtual ~logger_adapter()=default
void log(const std::string &message)
std::shared_ptr< logger_core > core_
size_t message_count() const
logger_adapter(std::shared_ptr< logger_core > core)
void log_internal(const std::string &message)
std::vector< std::string > messages_
std::chrono::system_clock::time_point timestamp_
size_t message_count() const
static std::unique_ptr< logger_adapter > create(integration_mode mode)
void log(const std::string &message)
void log_standalone(const std::string &message)
std::string get_interface_name() const override
void external_log(const std::string &message) override