-
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");
auto logger = std::make_shared<spdlog::async_logger>("as", some_sink, spdlog::thread_pool(), async_overflow_policy::block);
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)
- Replace the oldest message in the queue with the new one and never block if full - by using the
create_async_nb
factory function or by setting thespdlog::async_overflow_policy
in the logger's contructor:
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 tp create a new thread pool - 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);
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 ).