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:
- Standalone (default): Built-in async worker using
std::jthread
- IExecutor (v1.5.0+, Issue #253): Interface-based integration using
common_system::IExecutor
- 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.
executor_integration::enable();
auto executor = create_thread_pool_executor();
executor_integration::set_executor(executor);
executor_integration::submit_task([]() {
});
if (executor_integration::is_enabled()) {
std::cout << "Using " << executor_integration::get_executor_name() << "\n";
}
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
thread_system_integration::enable();
auto pool = std::make_shared<kcenon::thread::thread_pool>("my_logger_pool");
pool->start();
thread_system_integration::enable(pool);
if (thread_system_integration::is_enabled()) {
}
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:
- Search for
thread_system library
- Define
LOGGER_HAS_THREAD_SYSTEM compile definition
- 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:
static void enable(std::shared_ptr<kcenon::thread::thread_pool> pool =
nullptr);
[[nodiscard]] static std::shared_ptr<
kcenon::thread::
thread_pool> get_thread_pool() noexcept;
[[nodiscard]] static
bool submit_task(std::function<
void()> task);
};
}
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
Compile-time Detection
constexpr bool has_thread_system_support() noexcept;
if constexpr (has_thread_system_support()) {
} else {
}
Usage Patterns
Pattern 1: Application-wide Shared Pool
thread_system_integration::enable();
.value();
thread_system_integration::disable();
return 0;
}
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>
auto pool = std::make_shared<kcenon::thread::thread_pool>(
"high_perf_logger"
);
std::cerr << "Failed to start pool\n";
return 1;
}
thread_system_integration::enable(pool);
thread_system_integration::disable();
pool->stop();
return 0;
}
Pattern 3: Conditional Integration
void setup_logging() {
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():
- Check that pool was created successfully
- Verify pool is running (
pool->is_running())
- 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:
static void enable(std::shared_ptr<common::interfaces::IExecutor> executor =
nullptr);
[[nodiscard]] static executor_type get_executor_type() noexcept;
static
void set_executor(std::shared_ptr<
common::interfaces::IExecutor> executor);
[[nodiscard]] static std::shared_ptr<
common::interfaces::IExecutor> get_executor() noexcept;
[[nodiscard]] static
bool submit_task(std::function<
void()> task);
[[nodiscard]] static bool submit_task_delayed(std::function<void()> task,
std::chrono::milliseconds delay);
[[nodiscard]] static size_t pending_tasks() noexcept;
[[nodiscard]] static size_t worker_count() noexcept;
};
}
Stub implementation when IExecutor is not available.
static std::string get_executor_name() noexcept
static void enable() noexcept
static void disable() noexcept
static bool submit_task(std::function< void()>) noexcept
static constexpr bool is_enabled() noexcept
executor_type
enum class executor_type {
none,
external
};
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();
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;
};
class standalone_executor_factory {
public:
static std::shared_ptr<IExecutor> create(
std::size_t queue_size = 8192,
const std::string& name = "standalone_executor");
};
}
Compile-time Detection
constexpr bool has_executor_support() noexcept;
constexpr bool has_iexecutor_interface() noexcept;
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:
thread_system_integration::enable(pool);
thread_system_integration::submit_task(task);
#include <kcenon/thread/adapters/common_executor_adapter.h>
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