第三部分: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
  • 概述:本文代碼示例演示瞭如何在WPF中使用LiveCharts庫創建動態條形圖。通過創建數據模型、ViewModel和在XAML中使用`CartesianChart`控制項,你可以輕鬆實現圖表的數據綁定和動態更新。我將通過清晰的步驟指南包括詳細的中文註釋,幫助你快速理解並應用這一功能。 先上效果: 在 ...
  • openGauss(GaussDB ) openGauss是一款全面友好開放,攜手伙伴共同打造的企業級開源關係型資料庫。openGauss採用木蘭寬鬆許可證v2發行,提供面向多核架構的極致性能、全鏈路的業務、數據安全、基於AI的調優和高效運維的能力。openGauss深度融合華為在資料庫領域多年的研 ...
  • openGauss(GaussDB ) openGauss是一款全面友好開放,攜手伙伴共同打造的企業級開源關係型資料庫。openGauss採用木蘭寬鬆許可證v2發行,提供面向多核架構的極致性能、全鏈路的業務、數據安全、基於AI的調優和高效運維的能力。openGauss深度融合華為在資料庫領域多年的研 ...
  • 概述:本示例演示了在WPF應用程式中實現多語言支持的詳細步驟。通過資源字典和數據綁定,以及使用語言管理器類,應用程式能夠在運行時動態切換語言。這種方法使得多語言支持更加靈活,便於維護,同時提供清晰的代碼結構。 在WPF中實現多語言的一種常見方法是使用資源字典和數據綁定。以下是一個詳細的步驟和示例源代 ...
  • 描述(做一個簡單的記錄): 事件(event)的本質是一個委托;(聲明一個事件: public event TestDelegate eventTest;) 委托(delegate)可以理解為一個符合某種簽名的方法類型;比如:TestDelegate委托的返回數據類型為string,參數為 int和 ...
  • 1、AOT適合場景 Aot適合工具類型的項目使用,優點禁止反編 ,第一次啟動快,業務型項目或者反射多的項目不適合用AOT AOT更新記錄: 實實在在經過實踐的AOT ORM 5.1.4.117 +支持AOT 5.1.4.123 +支持CodeFirst和非同步方法 5.1.4.129-preview1 ...
  • 總說周知,UWP 是運行在沙盒裡面的,所有許可權都有嚴格限制,和沙盒外交互也需要特殊的通道,所以從根本杜絕了 UWP 毒瘤的存在。但是實際上 UWP 只是一個應用模型,本身是沒有什麼許可權管理的,許可權管理全靠 App Container 沙盒控制,如果我們脫離了這個沙盒,UWP 就會放飛自我了。那麼有沒... ...
  • 目錄條款17:讓介面容易被正確使用,不易被誤用(Make interfaces easy to use correctly and hard to use incorrectly)限制類型和值規定能做和不能做的事提供行為一致的介面條款19:設計class猶如設計type(Treat class de ...
  • title: 從零開始:Django項目的創建與配置指南 date: 2024/5/2 18:29:33 updated: 2024/5/2 18:29:33 categories: 後端開發 tags: Django WebDev Python ORM Security Deployment Op ...
  • 1、BOM對象 BOM:Broswer object model,即瀏覽器提供我們開發者在javascript用於操作瀏覽器的對象。 1.1、window對象 視窗方法 // BOM Browser object model 瀏覽器對象模型 // js中最大的一個對象.整個瀏覽器視窗出現的所有東西都 ...