Spdlog 是一個快速、異步的 C++ 日志庫,被廣泛應用于 C++ 專案中,在這篇文章中,我們將探討 Spdlog 日志庫的實作原理,
Spdlog 的結構
Spdlog 由五個主要組件構成:Loggers、Sinks、Formatters、Async Logger 和 Registry,每個組件都扮演著不同的角色,共同協作記錄并輸出日志訊息,
- Loggers :是 Spdlog 最基本的組件,負責記錄日志訊息,在 Spdlog 中,一個 Logger 物件代表著一個日志記錄器,應用程式可以使用 Logger 物件記錄不同級別的日志訊息,
- Sinks :決定了日志訊息的輸出位置,在 Spdlog 中,一個 Sink 物件代表著一個輸出位置,例如控制臺、檔案、網路等,應用程式可以將不同的日志訊息發送到不同的 Sink 中,
- Formatters :負責將日志訊息轉換為特定格式,在 Spdlog 中,一個 Formatter 物件代表著一個訊息格式器,應用程式可以使用不同的 Formatter 物件將日志訊息轉換為不同的格式,
- Async Logger :是 Spdlog 的異步記錄器,它負責將日志訊息異步地寫入到目標 Sink 中,當應用程式呼叫 Logger 物件記錄一個日志訊息時,該訊息會被加入到一個佇列中,然后異步地寫入目標 Sink 中,這樣可以避免多個執行緒同時訪問 Sink,從而確保執行緒安全性,
- Registry :用于管理 Spdlog 的所有組件,在 Spdlog 中,所有的 Loggers、Sinks、Formatters 和 Async Logger 都在一個全域注冊表中注冊,Registry 用于管理這些組件,

Spdlog 記錄日志的流程
當應用程式呼叫 Spdlog 記錄日志時,Spdlog 的流程如下:
- 獲取一個 Logger 物件,
- 使用該 Logger 物件記錄一個日志訊息,該訊息包括日志級別、時間戳、執行緒 ID、檔案名和行號等資訊,
- 將日志訊息傳遞給 Formatter,將訊息轉換為特定格式,
- 將格式化后的訊息傳遞給 Async Logger,
- Async Logger 將訊息寫入目標 Sink,完成日志記錄,
Spdlog 的流程非常簡單,但是每個組件都扮演著重要的角色,Loggers 負責記錄日志訊息,Sinks 決定了日志訊息的輸出位置,Formatters 負責將日志訊息轉換為特定格式,Async Logger 異步地將日志訊息寫入到目標 Sink 中,Registry 用于管理這些組件,
Spdlog 的執行緒安全性
spdlog 允許我們自由創建執行緒安全和非執行緒安全(單執行緒)的日志,其設定在基類base_skin 中,
template<typename Mutex>
class SPDLOG_API base_sink : public sink
{
public:
void log(const details::log_msg &msg) final;
protected:
Mutex mutex_;
}
template<typename Mutex>
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::log(const details::log_msg &msg)
{
std::lock_guard<Mutex> lock(mutex_);
sink_it_(msg);
}
每個sink都會繼承 base_sink,通過模板引數 Mutex 傳入鎖,可以看到寫日志函式 log 呼叫了 std::lock_guard 來使用鎖,
Mutex 可以自定義,需要提供下面兩個介面:
void lock();
void unlock();
在實際使用中如果想要執行緒安全,可以傳入c++的 mutex(c++11開始支持),也可以自定義,如下是一個宣告執行緒安全例子:
using kafka_sink_mt = kafka_sink<std::mutex>;
當然spdlog 也為我們提供了單執行緒的 mutex:
struct null_mutex
{
void lock() const {}
void unlock() const {}
};
using kafka_sink_st = kafka_sink<spdlog::details::null_mutex>;
Spdlog 的同步和異步模式
同步模式
在同步模式下,Spdlog 將日志訊息直接寫入目標 Sink,不使用記憶體佇列,這種模式下,應用程式在記錄日志訊息時,必須等待訊息寫入目標 Sink 后才能繼續執行,同步模式可以保證日志訊息的實時性,但是可能會影響程式的性能,特別是在大量記錄日志訊息時,如果應用程式不需要實時記錄日志訊息,可以使用異步模式來提高性能,
異步模式
在異步模式下,日志訊息被加入到一個記憶體佇列中,然后異步地寫入目標 Sink,異步模式可以提高日志記錄的性能,尤其是在多執行緒環境下,因為它可以避免多個執行緒同時訪問 Sink,從而提高執行緒安全性,
在 Spdlog 中,異步模式由 Async Logger 實作,Async Logger 在后臺運行一個執行緒,負責從記憶體佇列中獲取日志訊息,并將其寫入目標 Sink 中,Async Logger 可以配置多個 Sink,每個 Sink 都會有一個獨立的記憶體佇列,
Spdlog 提供了兩種記憶體佇列實作:unbounded 和 bounded,unbounded 記憶體佇列沒有大小限制,可以一直增長,直到記憶體耗盡,bounded 記憶體佇列有一個固定的大小,超過大小限制后,新的訊息將被丟棄,
在使用異步模式時,需要注意以下事項:
- 處理記憶體佇列時可能會出現記憶體分配問題和鎖競爭問題,需要謹慎設計和測驗,
- 如果記憶體佇列大小有限制,需要根據應用程式的需求和硬體資源進行適當的調整,
- 在應用程式退出時,需要等待所有日志訊息寫入完成,否則可能會丟失一些日志訊息,
異步模式可以大大提高日志記錄的性能,但是也需要謹慎使用和測驗,如果記憶體佇列大小限制不當或處理不當,可能會導致記憶體占用過高或日志訊息丟失等問題,
Spdlog 的性能
Spdlog 是一個高性能的日志庫,它的性能優于其他許多日志庫,Spdlog 的異步記錄器和多執行緒支持使得它能夠快速地記錄大量的日志訊息,
下面是spdlog性能:
同步模式:
[info] **************************************************************
[info] Single thread, 1,000,000 iterations
[info] **************************************************************
[info] basic_st Elapsed: 0.17 secs 5,777,626/sec
[info] rotating_st Elapsed: 0.18 secs 5,475,894/sec
[info] daily_st Elapsed: 0.20 secs 5,062,659/sec
[info] empty_logger Elapsed: 0.07 secs 14,127,300/sec
[info] **************************************************************
[info] C-string (400 bytes). Single thread, 1,000,000 iterations
[info] **************************************************************
[info] basic_st Elapsed: 0.41 secs 2,412,483/sec
[info] rotating_st Elapsed: 0.72 secs 1,389,196/sec
[info] daily_st Elapsed: 0.42 secs 2,393,298/sec
[info] null_st Elapsed: 0.04 secs 27,446,957/sec
[info] **************************************************************
[info] 10 threads, competing over the same logger object, 1,000,000 iterations
[info] **************************************************************
[info] basic_mt Elapsed: 0.60 secs 1,659,613/sec
[info] rotating_mt Elapsed: 0.62 secs 1,612,493/sec
[info] daily_mt Elapsed: 0.61 secs 1,638,305/sec
[info] null_mt Elapsed: 0.16 secs 6,272,758/sec
異步模式:
[info] -------------------------------------------------
[info] Messages : 1,000,000
[info] Threads : 10
[info] Queue : 8,192 slots
[info] Queue memory : 8,192 x 272 = 2,176 KB
[info] -------------------------------------------------
[info]
[info] *********************************
[info] Queue Overflow Policy: block
[info] *********************************
[info] Elapsed: 1.70784 secs 585,535/sec
[info] Elapsed: 1.69805 secs 588,910/sec
[info] Elapsed: 1.7026 secs 587,337/sec
[info]
[info] *********************************
[info] Queue Overflow Policy: overrun
[info] *********************************
[info] Elapsed: 0.372816 secs 2,682,285/sec
[info] Elapsed: 0.379758 secs 2,633,255/sec
[info] Elapsed: 0.373532 secs 2,677,147/sec
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/548322.html
標籤:其他
上一篇:【必須收藏】別再亂找TiDB 集群部署教程了,這篇保姆級教程來幫你!!| 博學谷狂野架構師
下一篇:MySQL面經
