-
Notifications
You must be signed in to change notification settings - Fork 4.6k
6. Asynchronous logging
There are several ways to create an asynchronous logger. In all ways you must #include spdlog/async.h
:
#include "spdlog/async.h"
void async_example()
{
// default thread pool settings can be modified *before* creating the async logger:
// spdlog::init_thread_pool(8192, 1); // queue with 8k items and 1 backing thread.
auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
}
auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
This will create a logger that will never block on full queue.
auto async_file = spdlog::create_async_nb<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
spdlog::init_thread_pool(queue_size, n_threads);
auto logger = std::make_shared<spdlog::async_logger>("as", some_sink, spdlog::thread_pool(), async_overflow_policy::block);
auto tp = std::make_shared<details::thread_pool>(queue_size, n_threads);
auto logger = std::make_shared<spdlog::async_logger>("as", some_sink, tp, async_overflow_policy::block);
Note: the tp object in the above example must outlive the logger object, since the logger acquires a weak_ptr to the tp.
There are 2 options on what to do when the queue is full:
- Block the caller until there is more room (default behaviour)
- Drop and replace the oldest messages in the queue with new ones instead of waiting for more room.
Use the
create_async_nb
factory function or thespdlog::async_overflow_policy
in the logger's constructor:
auto logger = spdlog::create_async_nb<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
// or directly:
auto logger = std::make_shared<async_logger>("as", test_sink, spdlog::thread_pool(), spdlog::async_overflow_policy::overrun_oldest);
By default, spdlog create a global thread pool with queue size of 8192 and 1 worker thread which to serve all async loggers.
This means that creating and destructing async loggers is cheap, since they do not own nor create any backing threads or queues- these are created and managed by the shared thread pool object.
All the queue slots are pre-allocated on thread-pool construction (each slot occupies ~256 bytes on 64bit systems)
The thread pool size and threads can be reset by
spdlog::init_thread_pool(queue_size, n_threads);
Note that this will drop the old global thread pool (tp) and create a new tp - which means that any loggers that use the old tp will stop working, so it is advised calling it before any async loggers created.
If different loggers must have separate queues, different instances of pools can be created and passed them to the loggers:
auto tp = std::make_shared<details::thread_pool>(128, 1);
auto logger = std::make_shared<async_logger>("as", some_sink, tp, async_overflow_policy::overrun_oldest);
auto tp2 = std::make_shared<details::thread_pool>(1024, 4); // create pool with queue of 1024 slots and 4 backing threads
auto logger2 = std::make_shared<async_logger>("as2", some_sink, tp2, async_overflow_policy::block);
Thread-pool has additional constructors that take callbacks as arguments. Those will be executed by each thread following its creation and prior to its destruction.
std::function<void()> on_start = []() { /* execute on start */ };
auto on_stop = []() { /* execute on stop */ };
auto tp = std::make_shared<details::thread_pool>(1024, 1, on_start, on_stop);
// init_thread_pool helper also supports optional on_start and on_stop callbacks
spdlog::init_thread_pool(1024, 1, on_start);
spdlog::init_thread_pool(1024, 1, on_start, on_stop);
By default, spdlog creates a single worker thread which preserves the order of the messages in the queue.
Please note that with thread pool with multiple workers threads, messages may be reordered after dequeuing.
If you want to keep the message order, create only one worker thread in the thread pool.
There is a bug in VS runtime that cause the application dead lock when it exits. If you use async logging, please make sure to call spdlog::shutdown()
before main() exit
(stackoverflow: std::thread join hangs if called after main exits when using vs2012 rc ).