Skip to content

6. Asynchronous logging

Gabi Melman edited this page Jul 20, 2018 · 53 revisions

Creating async loggers

There are several ways to create an asynchronous logger. In all ways you must #include spdlog/async.h:

Using the <spdlog::async_logger> template argument:

#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");
}

Using spdlog::create_async<Sink>:

auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");    

Using spdlog::create_async_nb<Sink>:

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");

Construct directly and use the global thread pool

auto logger = std::make_shared<spdlog::async_logger>("as", some_sink, spdlog::thread_pool(), async_overflow_policy::block);

Construct directly and use the a custom thread pool

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);

Construct directly and use the a custom thread pool

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.

Full queue policy

There are 2 options on what to do when the queue is full:

  • Block the caller until there is more room (default behaviour)
  • Ovewrride oldset message the message and never block - by setting the spdlog::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);

spdlog's thread pool

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, you create different instances of pools, passing them to different 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);

Windows issues

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::drop_all() before main() exit. If some loggers are not in the registry, those should be released manually as well. stackoverflow: std::thread join hangs if called after main exits when using vs2012 rc