How to Configure spdlog Async Thread Pool Size and Queue
Configure spdlog's async thread pool by calling spdlog::init_thread_pool(queue_size, thread_count) before instantiating any async loggers to set the global queue capacity and number of worker threads.
The spdlog library routes asynchronous log messages through a global lock-free multi-producer-multi-consumer queue processed by a shared thread pool. Because all async loggers created via spdlog::create_async share this single pool, you must configure the spdlog async thread pool size and queue capacity before creating your first logger.
Understanding the Global Thread Pool Architecture
spdlog implements asynchronous logging using a singleton details::thread_pool instance stored in the global registry. When you call spdlog::create_async, the logger obtains a reference to this pool via registry::instance().get_tp() and submits log messages to its lock-free queue.
Default Configuration Values
If you do not explicitly initialize the pool, spdlog lazily constructs it with default parameters defined in include/spdlog/async.h:
- Queue size:
8192items (details::default_async_q_size) - Thread count:
1worker thread
This default configuration works for light loads but requires adjustment for high-throughput applications to prevent queue overflow or thread contention.
Why Configuration Timing Matters
The pool must be configured before any async logger is instantiated. Once created, async loggers cache a reference to the current thread pool. While you can replace the pool by calling init_thread_pool again, existing loggers continue using the old pool reference, leading to inconsistent behavior.
Configuring the Async Thread Pool
Use spdlog::init_thread_pool to explicitly define the queue capacity and worker thread count. This function is declared in include/spdlog/async.h (lines 75-93) and implemented in src/async.cpp.
#include <spdlog/async.h>
#include <spdlog/sinks/stdout_sinks.h>
int main()
{
// Configure queue for 65536 messages with 2 worker threads
spdlog::init_thread_pool(65536, 2);
auto logger = spdlog::create_async<spdlog::sinks::stdout_sink_mt>("async_logger");
logger->info("Async logging configured");
}
The function signature accepts:
q_size: Maximum number of pending log messages (size_t)thread_count: Number of background threads processing the queue (size_t)- Optional
on_thread_startandon_thread_stopcallbacks for thread lifecycle management
Thread Callbacks
You can provide optional callbacks that execute in each worker thread during start and stop operations:
spdlog::init_thread_pool(
32768, // queue size
4, // threads
[]() { std::cout << "Worker thread started\n"; }, // on_thread_start
[]() { std::cout << "Worker thread stopped\n"; } // on_thread_stop
);
These callbacks are useful for setting thread priorities, CPU affinity, or initialization of thread-local resources.
Creating Async Loggers
After initializing the pool, create async loggers using template functions that automatically reference the global thread pool.
Blocking vs Non-Blocking Creation
spdlog::create_async: Uses the block-until-space policy. If the queue is full, the calling thread blocks until space becomes available.spdlog::create_async_nb: Uses the overrun-oldest policy. When the queue is full, the oldest message is dropped to make room for the new log entry.
// Blocking logger (default behavior)
auto blocking_logger = spdlog::create_async<spdlog::sinks::stdout_sink_mt>("blocking");
// Non-blocking logger (drops oldest entries when full)
auto nb_logger = spdlog::create_async_nb<spdlog::sinks::stdout_sink_mt>("non_blocking");
Choose create_async_nb for real-time systems where application responsiveness is more critical than complete log retention.
Querying Pool Status
Access the current thread pool instance using spdlog::thread_pool() to diagnose queue utilization:
auto tp = spdlog::thread_pool();
std::cout << "Queue capacity: " << tp->queue_size() << '\n';
This returns a std::shared_ptr<spdlog::details::thread_pool> allowing inspection of the pool configuration defined in include/spdlog/details/thread_pool.h.
Summary
- Single global pool: All async loggers share one
details::thread_poolinstance accessed via the registry. - Configure early: Call
spdlog::init_thread_pool(queue_size, thread_count)before anycreate_asynccall. - Default limits: Without explicit configuration, the pool starts with 8192 queue slots and 1 thread.
- Overflow policies: Use
create_asyncfor blocking behavior orcreate_async_nbto drop oldest messages when the queue fills. - Implementation files: Configuration logic resides in
include/spdlog/async.handsrc/async.cpp, with pool mechanics defined ininclude/spdlog/details/thread_pool.h.
Frequently Asked Questions
What is the default spdlog async queue size and thread count?
By default, spdlog initializes the async thread pool with a queue size of 8192 entries and 1 worker thread. This is defined by the details::default_async_q_size constant in include/spdlog/async.h. For production workloads, you should explicitly configure larger values using spdlog::init_thread_pool.
Can I change the thread pool size after creating async loggers?
While spdlog::init_thread_pool can replace the global pool at any time, existing async loggers retain references to the original pool instance. Therefore, changing the pool size only affects loggers created after the configuration change. Always initialize the pool before creating your loggers to ensure consistent behavior.
What happens when the spdlog async queue becomes full?
The behavior depends on the logger type. Blocking loggers (created with spdlog::create_async) will block the calling thread until space is available in the queue. Non-blocking loggers (created with spdlog::create_async_nb) implement the overrun-oldest policy, discarding the oldest log message to accommodate new entries when the queue reaches capacity.
How many threads should I configure for spdlog async logging?
The optimal thread count depends on your sink throughput and CPU cores. For most applications, 1-2 threads suffice since the queue is lock-free and threads primarily serialize to the sink. Multi-threaded sinks (like stdout_sink_mt) may benefit from 2-4 threads to handle I/O bottlenecks, but avoid over-subscribing CPU cores to prevent context-switching overhead.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →