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

autotoc_md2379

doc_id: "LOG-GUID-026" doc_title: "Async Integration Guide" doc_version: "1.0.0" doc_date: "2026-04-04" doc_status: "Released" project: "logger_system"

category: "GUID"

Async Integration Guide

SSOT: This document is the single source of truth for Async Integration Guide.

Language: English | 한국어

Overview

This guide explains how to enable and use async processing integration in logger_system.

Since v3.1.0 (Issue #222), logger_system uses a standalone std::jthread-based async worker by default. Multiple integration options are available:

  1. Standalone (default): Built-in async worker using std::jthread
  2. IExecutor (v1.5.0+, Issue #253): Interface-based integration using common_system::IExecutor
  3. thread_system (legacy): Direct integration with thread_system::thread_pool

Integration Approaches

Recommended: IExecutor Interface (v1.5.0+)

The executor_integration module provides IExecutor-based async processing without compile-time dependency on thread_system. This is the recommended approach for new projects.

// Option 1: Enable with default standalone executor
executor_integration::enable();
// Option 2: Enable with custom IExecutor (e.g., from thread_system)
auto executor = create_thread_pool_executor(); // Your executor
executor_integration::set_executor(executor);
// Submit tasks
executor_integration::submit_task([]() {
// async work
});
// Check status
if (executor_integration::is_enabled()) {
std::cout << "Using " << executor_integration::get_executor_name() << "\n";
}
// Disable when done
executor_integration::disable();
IExecutor-based async integration for logger_system.

Legacy: Direct thread_system Integration

For projects already using thread_system directly, the thread_system_integration module is still available.

Quick Start

Enable at Build Time

cmake -S . -B build -DLOGGER_USE_THREAD_SYSTEM=ON
cmake --build build

Enable at Runtime

// Option 1: Enable with default thread pool
thread_system_integration::enable();
// Option 2: Enable with custom thread pool
auto pool = std::make_shared<kcenon::thread::thread_pool>("my_logger_pool");
pool->start();
thread_system_integration::enable(pool);
// Check if enabled
if (thread_system_integration::is_enabled()) {
// Using thread_pool backend
}
// Disable when done
thread_system_integration::disable();
Optional thread_system integration for advanced async processing.

Configuration

CMake Options

Option Default Description
LOGGER_USE_THREAD_SYSTEM OFF Enable optional thread_system integration

When enabled, CMake will:

  1. Search for thread_system library
  2. Define LOGGER_HAS_THREAD_SYSTEM compile definition
  3. Link LoggerSystem with thread_system

Compile Definitions

Definition When Defined Effect
LOGGER_HAS_THREAD_SYSTEM LOGGER_USE_THREAD_SYSTEM=ON and thread_system found Enables full integration API

Dependency Configuration

Bidirectional Dependency Risk (Issue #252 — Resolved)

Resolved: The bidirectional dependency risk has been resolved. thread_system's BUILD_WITH_LOGGER_SYSTEM is deprecated (thread_system#336) and scheduled for removal in v0.5.0.0. thread_system now uses ILogger dependency injection from common_system instead. See docs/DEPENDENCY_ARCHITECTURE.md for the resolved dependency graph.

Previously, both logger_system and thread_system could optionally depend on each other:

┌──────────────────────┐
│ thread_system │
│ │
│ BUILD_WITH_LOGGER_ │◄──── Uses for debug output
│ SYSTEM │
└──────────┬───────────┘
BUILD_WITH_ │ LOGGER_USE_
LOGGER_SYSTEM │ THREAD_SYSTEM
┌──────────▼───────────┐
│ logger_system │
│ │
│ LOGGER_HAS_THREAD_ │◄──── Uses for async I/O
│ SYSTEM │
└──────────────────────┘

WARNING: Enabling both directions simultaneously creates circular dependency risk.

Recommended Configuration Matrix

Use Case thread→logger logger→thread CMake Flags Notes
Logger standalone OFF OFF (default) Minimal build, internal std::jthread
Logger with thread_pool OFF ON LOGGER_USE_THREAD_SYSTEM=ON Recommended for async I/O
Thread with debug logging ON OFF BUILD_WITH_LOGGER_SYSTEM=ON For debugging thread_system
Production OFF ON LOGGER_USE_THREAD_SYSTEM=ON Avoid reverse for production

Safe Configuration Examples

Recommended: Logger uses thread_system (one-way)

# logger_system → thread_system only
cmake -B build \
-DLOGGER_USE_THREAD_SYSTEM=ON \
-DBUILD_WITH_LOGGER_SYSTEM=OFF

Standalone mode (no cross-dependency)

# No integration, minimal dependencies
cmake -B build \
-DLOGGER_USE_THREAD_SYSTEM=OFF

NOT recommended: Bidirectional dependency

# WARNING: May cause build order issues
cmake -B build \
-DLOGGER_USE_THREAD_SYSTEM=ON \
-DBUILD_WITH_LOGGER_SYSTEM=ON # Avoid this combination!

CMake Conflict Detection

logger_system includes automatic detection for bidirectional dependency risk. When both directions are enabled, CMake will emit a warning:

=================================================================
BIDIRECTIONAL DEPENDENCY RISK DETECTED (Issue #252)
=================================================================
logger_system → thread_system (LOGGER_USE_THREAD_SYSTEM=ON)
thread_system → logger_system (BUILD_WITH_LOGGER_SYSTEM=ON)
This configuration may cause:
- Build order issues in unified builds
- Circular header include problems
- Initialization order complications
RECOMMENDATION:
Enable only ONE direction. Preferred configuration:
LOGGER_USE_THREAD_SYSTEM=ON (for async I/O performance)
BUILD_WITH_LOGGER_SYSTEM=OFF (disable reverse dependency)
=================================================================

API Reference

thread_system_integration

Static class providing thread_system integration management.

Methods

public:
// Enable thread_pool backend (creates default pool if nullptr)
static void enable(std::shared_ptr<kcenon::thread::thread_pool> pool = nullptr);
// Disable and fall back to standalone backend
static void disable();
// Check if thread_pool backend is active
[[nodiscard]] static bool is_enabled() noexcept;
// Get current backend type
[[nodiscard]] static async_backend_type get_backend() noexcept;
// Set/get custom thread pool
static void set_thread_pool(std::shared_ptr<kcenon::thread::thread_pool> pool);
[[nodiscard]] static std::shared_ptr<kcenon::thread::thread_pool> get_thread_pool() noexcept;
// Submit task to thread_pool (returns false if not enabled)
[[nodiscard]] static bool submit_task(std::function<void()> task);
// Get backend name for diagnostics
[[nodiscard]] static std::string get_backend_name() noexcept;
};
} // namespace kcenon::logger::integration
Stub implementation when thread_system is not available.
static std::string get_backend_name() noexcept
Always returns "standalone" when thread_system is not available.
static void disable() noexcept
No-op when thread_system is not available.
static void enable() noexcept
No-op when thread_system is not available.
static constexpr async_backend_type get_backend() noexcept
Always returns standalone when thread_system is not available.
static constexpr bool is_enabled() noexcept
Always returns false when thread_system is not available.
static bool submit_task(std::function< void()>) noexcept
Always returns false when thread_system is not available.
async_backend_type
Backend type enumeration for async processing.
@ thread_pool
Thread pool backend using thread_system.

async_backend_type

enum class async_backend_type {
standalone, // Default std::jthread-based worker
thread_pool // thread_system's thread_pool
};

Compile-time Detection

// Check if thread_system support is available
constexpr bool has_thread_system_support() noexcept;
// Usage
if constexpr (has_thread_system_support()) {
// Use thread_system features
} else {
// Use standalone features only
}

Usage Patterns

Pattern 1: Application-wide Shared Pool

using namespace kcenon::logger;
int main() {
// Enable thread_system integration at startup
thread_system_integration::enable();
// Create logger - will use thread_pool if available
.use_template("production")
.build()
.value();
// ... application code ...
// Cleanup at shutdown
thread_system_integration::disable();
return 0;
}
int main()
Builder pattern for logger construction with validation.
logger_builder & use_template(const std::string &name)
result< std::unique_ptr< logger > > build()
Builder pattern implementation for flexible logger configuration kcenon.

Pattern 2: Custom Pool Configuration

#include <kcenon/thread/core/thread_pool.h>
int main() {
// Create custom thread pool with specific settings
auto pool = std::make_shared<kcenon::thread::thread_pool>(
"high_perf_logger"
);
// Start the pool
auto result = pool->start();
if (!result) {
std::cerr << "Failed to start pool\n";
return 1;
}
// Use custom pool for logging
thread_system_integration::enable(pool);
// ... application code ...
// Cleanup
thread_system_integration::disable();
pool->stop();
return 0;
}

Pattern 3: Conditional Integration

void setup_logging() {
using namespace kcenon::logger::integration;
// Only enable if thread_system is available
if constexpr (has_thread_system_support()) {
thread_system_integration::enable();
std::cout << "Using " << thread_system_integration::get_backend_name()
<< " backend\n";
} else {
std::cout << "Using standalone backend (thread_system not available)\n";
}
}

Thread Safety

All thread_system_integration methods are thread-safe:

  • Backend state changes are atomic
  • Pool access is protected by mutex
  • Multiple threads can safely call enable()/disable()

Performance Considerations

When to Use thread_system Integration

Use thread_pool backend when:

  • Multiple loggers share the same thread pool
  • You need priority-based log processing
  • Advanced metrics and monitoring are required
  • Your application already uses thread_system

Use standalone backend when:

  • Minimal dependencies are preferred
  • Single logger per application
  • Logging overhead should be minimal
  • thread_system is not available

Overhead Comparison

Backend Task Submission Memory Dependencies
Standalone ~50ns Lower None
thread_pool ~100ns Higher thread_system

Troubleshooting

thread_system not found

-- Logger System: thread_system not found, using standalone mode

Solution: Ensure thread_system is installed or available via FetchContent:

set(UNIFIED_USE_LOCAL ON) # Use local sibling directories
cmake -DLOGGER_USE_THREAD_SYSTEM=ON ..

Runtime detection not working

If is_enabled() returns false after enable():

  1. Check that pool was created successfully
  2. Verify pool is running (pool->is_running())
  3. Check for errors in pool creation
auto pool = thread_system_integration::get_thread_pool();
if (pool) {
std::cout << "Pool running: " << pool->is_running() << "\n";
} else {
std::cout << "No pool configured\n";
}

IExecutor Integration API (v1.5.0+)

executor_integration

Static class providing IExecutor-based integration management.

public:
// Enable async processing (creates default standalone executor if nullptr)
static void enable(std::shared_ptr<common::interfaces::IExecutor> executor = nullptr);
// Disable async processing
static void disable();
// Check if async processing is enabled
[[nodiscard]] static bool is_enabled() noexcept;
// Get current executor type
[[nodiscard]] static executor_type get_executor_type() noexcept;
// Set/get executor
static void set_executor(std::shared_ptr<common::interfaces::IExecutor> executor);
[[nodiscard]] static std::shared_ptr<common::interfaces::IExecutor> get_executor() noexcept;
// Submit task
[[nodiscard]] static bool submit_task(std::function<void()> task);
[[nodiscard]] static bool submit_task_delayed(std::function<void()> task,
std::chrono::milliseconds delay);
// Metrics
[[nodiscard]] static std::string get_executor_name() noexcept;
[[nodiscard]] static size_t pending_tasks() noexcept;
[[nodiscard]] static size_t worker_count() noexcept;
};
} // namespace kcenon::logger::integration
Stub implementation when IExecutor is not available.
static bool submit_task(std::function< void()>) noexcept

executor_type

enum class executor_type {
none, // No executor configured
standalone, // Built-in standalone executor
external // User-provided IExecutor
};

standalone_executor

Built-in IExecutor implementation using a single worker thread.

class standalone_executor : public common::interfaces::IExecutor {
public:
explicit standalone_executor(std::size_t queue_size = 8192,
std::string name = "standalone_executor");
void start();
// IExecutor interface
Result<std::future<void>> execute(std::unique_ptr<IJob>&& job) override;
Result<std::future<void>> execute_delayed(std::unique_ptr<IJob>&& job,
std::chrono::milliseconds delay) override;
size_t worker_count() const override;
bool is_running() const override;
size_t pending_tasks() const override;
void shutdown(bool wait_for_completion = true) override;
};
// Factory for creating standalone executors
class standalone_executor_factory {
public:
static std::shared_ptr<IExecutor> create(
std::size_t queue_size = 8192,
const std::string& name = "standalone_executor");
};
} // namespace kcenon::logger::integration

Compile-time Detection

// Check if IExecutor support is available
constexpr bool has_executor_support() noexcept;
// Check if IExecutor interface is detected
constexpr bool has_iexecutor_interface() noexcept;
// Usage
if constexpr (has_executor_support()) {
executor_integration::enable();
}

Migration from thread_system_integration

If you're currently using thread_system_integration, you can migrate to executor_integration:

// Before (legacy)
thread_system_integration::enable(pool);
thread_system_integration::submit_task(task);
// After (recommended)
#include <kcenon/thread/adapters/common_executor_adapter.h>
// Wrap thread_pool in IExecutor adapter
auto executor = kcenon::thread::adapters::common_executor_factory::create_from_thread_pool(pool);
executor_integration::set_executor(executor);
executor_integration::submit_task(task);

Related Documentation


Last updated: 2025-12