第三部分:Spdlog 日誌庫的實現原理

来源:https://www.cnblogs.com/listenwind666/archive/2023/03/27/17262275.html
-Advertisement-
Play Games

Spdlog 是一個快速、非同步的 C++ 日誌庫,被廣泛應用於 C++ 項目中。在這篇文章中,我們將探討 Spdlog 日誌庫的實現原理。 Spdlog 的結構 Spdlog 由五個主要組件構成:Loggers、Sinks、Formatters、Async Logger 和 Registry。每個組 ...


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 用於管理這些組件。

Image

Spdlog 記錄日誌的流程

當應用程式調用 Spdlog 記錄日誌時,Spdlog 的流程如下:

  1. 獲取一個 Logger 對象。
  2. 使用該 Logger 對象記錄一個日誌消息,該消息包括日誌級別、時間戳、線程 ID、文件名和行號等信息。
  3. 將日誌消息傳遞給 Formatter,將消息轉換為特定格式。
  4. 將格式化後的消息傳遞給 Async Logger。
  5. 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

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.去除0的方法 BigDecimal是處理高精度的浮點數運算的常用的一個類 當需要將BigDecimal中保存的浮點數值列印出來,特別是在頁面上顯示的時候,就有可能遇到預想之外的科學技術法表示的問題。 一般直接使用 BigDecimal.toString()方法即可以完成浮點數的列印。 如: Sy ...
  • 使用 VLD 記憶體泄漏檢測工具輔助開發時整理的學習筆記。本篇介紹 VLD 配置文件中配置項 ForceIncludeModules 的使用方法。 ...
  • sychronized是java多線程非常關鍵的一個知識點,這篇博客將從synchronized幾個用法以及代碼來學習。 sychronized的作用是能夠保證同一時間只有一個線程來運行這塊代碼,達到併發效果,如果沒有保證併發的話,在多線程編碼中就會產生致命問題,比如經典的i++,這也是資料庫併發中 ...
  • 使用 VLD 記憶體泄漏檢測工具輔助開發時整理的學習筆記。本篇介紹 VLD 配置文件中配置項 AggregateDuplicates 的使用方法。 ...
  • 本篇將對 Yarn 調度器中的資源搶占方式進行探究。分析當集群資源不足時,占用量資源少的隊列,是如何從其他隊列中搶奪資源的。我們將深入源碼,一步步分析搶奪資源的具體邏輯。 ...
  • 什麼是 Spdlog 日誌庫 Spdlog 是一個 C++ 的日誌庫,它具有高效、易用、跨平臺等特點。它可以寫入到控制台、文件等輸出目標,支持多種日誌級別、多線程安全等功能,非常適合在 C++ 項目中使用。 Spdlog 日誌庫的歷史和背景 Spdlog 日誌庫最初由 Gabi Melman 開發, ...
  • Sass IT寶庫整理的SASS快速參考備忘單,列出了 SASS 最有用的功能Sass 基礎,為開發人員分享快速參考備忘單。 Sass 是 Syntactically Awesome Stylesheets 的簡寫,是一個最初由 Hampton Catlin 設計並由 Natalie Weizenb ...
  • 內容援引自JavaGuide、嗶哩嗶哩黑馬程式員資料庫從入門到精通,感謝各位大神原創分享 資料庫Mysql 常見的關係型資料庫包括mysql、SQL Server、Oracle、常見的非關係型資料庫Redis、MongDB等。 特點 Mysql開源免費,生態完善,支持事務、高可用(讀寫分離、分庫分表 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...