第三部分: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
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...