非同期ロガーの作成
非同期ロガーを作成する方法はいくつかあります。いずれの方法でも、#include spdlog/async.h が必要です。
テンプレート引数 <spdlog::async_factory> を使う
#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");
}spdlog::create_async<Sink> を使う
auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt"); spdlog::create_async_nb<Sink> を使う
キューが満杯でもブロックしないロガーを作成します。
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);注意:上の例のロガーはtpへのweak_ptrを取得するため、tpオブジェクトの寿命はロガーオブジェクトより長くなければなりません。
キューが満杯のときの方針
キューが満杯のときにどうするか、2つの選択肢があります。
- 空きができるまで呼び出し元をブロックする(デフォルトの動作)。
- 空きを待つ代わりに、キュー内の最も古いメッセージを破棄して、新しいメッセージに置き換える。
create_async_nbファクトリ関数、またはロガーのコンストラクターのspdlog::async_overflow_policyを使います。
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のスレッドプール
デフォルトでは、spdlogはキューサイズ8192、ワーカースレッド1個のグローバルスレッドプールを作成し、すべての非同期ロガーで使用します。
非同期ロガー自身は処理用のスレッドやキューを所有せず、作成もしません。それらは共有スレッドプールオブジェクトによって作成・管理されるため、非同期ロガーの作成・破棄のコストは小さくなります。
キューのすべてのスロットは、スレッドプールの構築時に事前割り当てされます(64ビットシステムでは、各スロットが約256バイトを占めます)。
スレッドプールのサイズとスレッド数は、次のようにリセットできます。
spdlog::init_thread_pool(queue_size, n_threads);これにより古いグローバルスレッドプール(tp)が破棄され、新しいtpが作成される点に注意してください。古いtpを使っているロガーは動作しなくなるため、非同期ロガーを作成する前に呼び出すことを推奨します。
ロガーごとに別々のキューが必要な場合は、プールの異なるインスタンスを作成して、それぞれのロガーに渡せます。
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);スレッドプールには、コールバックを引数として受け取るコンストラクターもあります。各スレッドの作成後、および破棄前に、そのスレッドで実行されます。
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);メッセージの順序
デフォルトでは、spdlogはワーカースレッドを1個作成し、キュー内のメッセージの順序を保持します。
ワーカースレッドが複数あるスレッドプールでは、キューから取り出された後にメッセージの順序が変わる可能性がある点に注意してください。
メッセージの順序を保ちたい場合は、スレッドプール内のワーカースレッドを1個だけ作成してください。
Windowsに関する問題
VSランタイムには、アプリケーション終了時にデッドロックを引き起こすバグがあります。非同期ログを使う場合は、main()が終了する前に spdlog::shutdown() を必ず呼び出してください。
(stackoverflow:VS2012 RCでmain終了後に呼び出すとstd::threadのjoinが停止する)。
©gabime 2023-2024 spdlog. All Rights Reserved.