spdlog 基本結構分析

spdlog 基本結構分析

代碼取自 V1.5.0, 代碼堪稱美學。git

spdlog 是一個只有頭文件的C++日誌庫,速度很是快,擴展性很強,更重要的是 社區活躍,文檔齊全github

使用

  1. 參考官方的 example.
  2. {fmt} 的格式使用也須要熟悉一下,畢竟也進 C++20 了,什麼垃圾流就快掃進歷史的垃圾堆吧.

分析

這裏選擇了三個點來作分析:後端

  1. 提供的 日誌格式 很是豐富,而且容許用戶自定義須要的格式。
  2. 對日誌文件的類型也作了充分擴展,支持控制檯,普通文件,按大小滾動文件,按時間滾動文件,若是不能知足須要,能夠本身擴展格式,見 spdlog/sinks/base_sink.h
  3. 支持單/多線程,異步/同步,阻塞非阻塞模式。

spdlog 的代碼結構以下:多線程

spdlog
    ├─example  用法代碼
    ├─include  實現目錄
    │  └─spdlog
    │      ├─details  功能函數目錄
    │      ├─fmt  {fmt} 庫目錄
    │      ├─sinks  落地文件格式實現
    │      └─*.h    異步模式,日誌庫接口等實現
    ├─src  .cpp 文件,組成編譯模塊生成靜態庫使用
    ├─test  測試代碼

基本邏輯結構以下:
異步

有幾個比較重要的文件:async

  • spdlog/spdlog.h 爲日誌庫接口,提供日誌宏的屬性控制函數。
  • spdlog/logger.h 爲日誌管理器,爲先後端鏈接的樞紐。
  • spdlog/async.h 爲異步模式接口。
  • spdlog/sinks/base_sink.h 爲日誌文件格式父類,後面全部的日誌文件格式都是繼承該類來實現不一樣功能。
  • spdlog/sinks/registry.h 用於登記全部的logger,及一些默認的屬性,如日誌格式、日誌寫入等級。

spdlog 接口

spdlog 整體而言提供了日誌接口函數

  1. spdlog::debug(), 默認的日誌對象,使用默認的日誌信息格式,輸出至 stdout。
  2. logger->debug(), 指定日誌對象進行日誌記錄,輸出至該日誌對象對應的文件中。
  3. SPDLOG_LOGGER_DEBUG(logger), SPDLOG_DEBUG(), 使用宏對以上兩種接口進行包裝,產生的日誌格式包含 文件、函數、行。

提供的一些落地的文件類型:測試

  • 標準輸出
  • 帶顏色的標準輸出(默認)
  • 基本文件
  • 可設定時間的滾動文件
  • 可設定大小的滾動文件
  • 過濾重複的日誌
  • syslog 日誌

這裏簡單提一下 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 管理全部的日誌對象

  1. 使用 <name, logger> 將日誌對象和其名稱對應起來,後面使用的時候能夠直接經過名稱獲取對應的日誌對象。
  2. 保存所有日誌對象的默認屬性,可以使用提供的屬性控制接口改變全部的日誌對象屬性。
  3. 提供定時flush,spdlog 的文件操做具備緩衝區屬性,爲試日誌信息及時落地,後臺新生成一個flush線程,設置一個時間(單位:秒)定時喚醒一次進行 flush。

參考

  1. {fmt}, A modern formatting library. 現代化的格式化庫,速度快,使用簡單,已經肯定進入 C++20.
相關文章
相關標籤/搜索