第三部分: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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...