代碼取自 V1.5.0, 代碼堪稱美學。git
spdlog 是一個只有頭文件的C++日誌庫,速度很是快,擴展性很強,更重要的是 社區活躍,文檔齊全。github
這裏選擇了三個點來作分析:後端
spdlog 的代碼結構以下:多線程
spdlog ├─example 用法代碼 ├─include 實現目錄 │ └─spdlog │ ├─details 功能函數目錄 │ ├─fmt {fmt} 庫目錄 │ ├─sinks 落地文件格式實現 │ └─*.h 異步模式,日誌庫接口等實現 ├─src .cpp 文件,組成編譯模塊生成靜態庫使用 ├─test 測試代碼
基本邏輯結構以下:
異步
有幾個比較重要的文件:async
spdlog 整體而言提供了日誌接口函數
spdlog::debug()
, 默認的日誌對象,使用默認的日誌信息格式,輸出至 stdout。logger->debug()
, 指定日誌對象進行日誌記錄,輸出至該日誌對象對應的文件中。SPDLOG_LOGGER_DEBUG(logger), SPDLOG_DEBUG()
, 使用宏對以上兩種接口進行包裝,產生的日誌格式包含 文件、函數、行。提供的一些落地的文件類型:測試
這裏簡單提一下 sinks 的實現,全部落地文件的類型都是從 base_sink
(忽略sink) 繼承而來,提供了兩個純虛函數 sink_it_()
和 flush_()
,這樣一來,須要擴展的類型文件只須要實現兩個函數,很大的簡化了擴展的流程。而單/多線程經過模板來肯定是否須要使用互斥量來保持同步,也算是比較有意思的一個實現了:線程
// 例子使用 base_file_sink using basic_file_sink_mt = basic_file_sink<std::mutex>; using basic_file_sink_st = basic_file_sink<details::null_mutex>; struct null_mutex { void lock() const {} void unlock() const {} bool try_lock() const { return true; } }; 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); }
若是須要使用多線程模式,就使用 std::mutex
,若是是單線程,咱們就不須要互斥來同步,這裏實現一個空的互斥量類,就使得 log() 的代碼徹底不須要修改了,也提升了內聚性。debug
spdlog 默認使用同步模式,也能夠設置異步模式,異步模式會建立一個線程池,線程池大小能夠自行設置,默認爲1,該線程池全部者爲 details::registry::instance()
. 後臺的大小能夠設置的 多生產者多消費者隊列 默認爲阻塞模式,也能夠設置爲非阻塞,不過這個非阻塞的處理很是簡單粗暴,就是簡單的丟棄最老的日誌,推薦是不要這樣設置滴,通常產生阻塞的狀況大概是磁盤IO打滿了,出現這個狀況通常是別的地方出問題了。
details::registry
管理全部的日誌對象
<name, logger>
將日誌對象和其名稱對應起來,後面使用的時候能夠直接經過名稱獲取對應的日誌對象。