C++ spdlog日志庫(kù)示例詳解
一、spdlog日志庫(kù)詳解
C++的 spdlog 日志庫(kù)。這是一款高性能、功能豐富且易于使用的開源日志庫(kù)。
1. 概述與核心優(yōu)勢(shì)
- 高性能: 這是
spdlog的核心設(shè)計(jì)目標(biāo)之一。它采用了異步日志記錄機(jī)制(可選),將日志消息的格式化、寫入等耗時(shí)操作放入后臺(tái)線程執(zhí)行,極大地減少了對(duì)主線程性能的影響。其性能通常優(yōu)于許多其他C++日志庫(kù)。 - 極簡(jiǎn)的頭部引用: 只需包含一個(gè)頭文件
#include <spdlog/spdlog.h>即可開始使用基本功能。 - 豐富的特性:
- 支持多種日志級(jí)別(trace, debug, info, warn, error, critical)。
- 支持多種日志目標(biāo)(控制臺(tái)、文件、系統(tǒng)日志、TCP套接字、UDP套接字、Rotating files - 滾動(dòng)文件、Daily files - 每日文件、Windows debugger 等)。
- 支持自定義格式(使用類似
printf的格式化語(yǔ)法或自定義模式)。 - 支持多線程安全。
- 支持異步日志(默認(rèn)是同步的,但可以輕松配置為異步)。
- 支持日志刷新策略。
- 支持自定義日志器(logger)和接收器(sink)。
- 支持全局和特定日志器。
- 易用性: API設(shè)計(jì)簡(jiǎn)潔直觀,學(xué)習(xí)曲線平緩。
2. 核心概念
- 日志器(Logger): 日志記錄的核心對(duì)象。每個(gè)日志器可以有:
- 名稱: 用于標(biāo)識(shí)和檢索。
- 日志級(jí)別: 決定哪些級(jí)別的消息會(huì)被實(shí)際記錄。低于設(shè)置級(jí)別的消息會(huì)被忽略。
- 接收器(Sinks)列表: 一個(gè)或多個(gè)輸出目標(biāo)。日志消息會(huì)被發(fā)送到所有關(guān)聯(lián)的接收器。
- 錯(cuò)誤處理器: 當(dāng)寫入失敗時(shí)的回調(diào)函數(shù)。
- 格式化器: 控制日志消息的輸出格式。
- 接收器(Sink): 負(fù)責(zé)將格式化后的日志消息輸出到具體的目標(biāo)。
spdlog提供了多種內(nèi)置接收器:stdout_sink_mt,stderr_sink_mt: 輸出到標(biāo)準(zhǔn)輸出/標(biāo)準(zhǔn)錯(cuò)誤(多線程安全)。basic_file_sink_mt: 輸出到文件(多線程安全)。rotating_file_sink_mt: 基于文件大小的滾動(dòng)日志文件。daily_file_sink_mt: 基于時(shí)間的每日日志文件(每天或指定時(shí)間創(chuàng)建新文件)。syslog_sink_mt: 輸出到Unix系統(tǒng)日志(如/var/log/syslog)。win_eventlog_sink_mt: 輸出到Windows事件查看器。msvc_sink_mt: 輸出到Visual Studio調(diào)試窗口(僅Windows)。tcp_sink_mt,udp_sink_mt: 輸出到網(wǎng)絡(luò)套接字。dist_sink_mt: 分布式接收器,將消息分發(fā)到多個(gè)其他接收器。null_sink_mt: 丟棄所有日志消息(用于測(cè)試或禁用)。ostream_sink_mt: 輸出到任意std::ostream。ansicolor_sink: 支持ANSI顏色代碼的控制臺(tái)輸出。android_sink: Android平臺(tái)日志輸出。
- 格式化器(Formatter): 定義了每條日志消息的最終輸出格式。它使用特定的模式字符串來指定如何組合時(shí)間戳、日志級(jí)別、日志器名稱、線程ID、消息內(nèi)容等。
spdlog默認(rèn)使用類似以下格式:對(duì)應(yīng):[%Y-%m-%d %H:%M:%S.%e] [%l] [%t] %v
[日期 時(shí)間] [級(jí)別] [線程ID] 消息正文
你可以使用set_pattern自定義格式。 - 日志級(jí)別: 定義了日志消息的嚴(yán)重性,從低到高依次為:
spdlog::level::tracespdlog::level::debugspdlog::level::infospdlog::level::warnspdlog::level::errspdlog::level::criticalspdlog::level::off(關(guān)閉所有日志)
每個(gè)日志器都有自己的級(jí)別,低于該級(jí)別的消息不會(huì)被記錄。全局默認(rèn)級(jí)別可以通過spdlog::set_level設(shè)置。
3. 基本用法
#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h> // 文件接收器
#include <spdlog/sinks/stdout_color_sinks.h> // 帶顏色的控制臺(tái)接收器
int main() {
// 創(chuàng)建一個(gè)同時(shí)輸出到控制臺(tái)(帶顏色)和文件的日志器
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/basic-log.txt", true); // true 表示覆蓋而非追加
std::vector<spdlog::sink_ptr> sinks{console_sink, file_sink};
auto logger = std::make_shared<spdlog::logger>("my_logger", sinks.begin(), sinks.end());
// 設(shè)置日志級(jí)別 (全局設(shè)置也可以使用 spdlog::set_level)
logger->set_level(spdlog::level::debug);
// 設(shè)置輸出格式 (可選,這里設(shè)置一個(gè)簡(jiǎn)潔格式)
logger->set_pattern("[%H:%M:%S] [%l] %v");
// 注冊(cè)此日志器,之后可通過名稱獲取 (可選)
spdlog::register_logger(logger);
// 使用默認(rèn)全局日志器 (快速開始)
spdlog::info("This is an info message using the default global logger.");
spdlog::warn("This is a warning message.");
// 使用我們創(chuàng)建的日志器
logger->debug("This is a debug message.");
logger->error("Some error occurred: {}", 42); // 格式化,類似 `printf`
logger->critical("Critical error! Exiting...");
// 刷新日志 (確保所有消息都寫入目標(biāo),特別是對(duì)于文件。異步日志器通常自動(dòng)處理)
logger->flush();
// 通過名稱獲取已注冊(cè)的日志器
auto same_logger = spdlog::get("my_logger");
same_logger->info("Retrieved logger by name.");
return 0;
}
4. 高級(jí)用法與特性
異步日志: 創(chuàng)建異步日志器可以顯著提升性能,尤其在高頻日志場(chǎng)景。
#include <spdlog/async.h>
#include <spdlog/sinks/rotating_file_sink.h>
int main() {
// 創(chuàng)建一個(gè)異步日志器工廠 (通常全局一個(gè)足夠)
auto async_factory = spdlog::create_async<my_logger_name>("async_logger");
// 添加接收器 (例如一個(gè)滾動(dòng)文件接收器)
auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("logs/rotating-log.txt", 1024 * 1024 * 5, 3); // 5MB大小,保留3個(gè)備份
async_factory->add_sink(rotating_sink);
// 設(shè)置級(jí)別、格式等
async_factory->set_level(spdlog::level::info);
async_factory->set_pattern("%^[%L]%$ %v"); // %^ %$ 用于顏色控制
// 獲取并使用異步日志器
auto async_logger = spdlog::get("async_logger");
async_logger->info("This message is logged asynchronously.");
// 結(jié)束時(shí),確保關(guān)閉異步日志器 (釋放后臺(tái)線程)
spdlog::drop_all(); // 或者單獨(dú) drop("async_logger")
return 0;
}- 自定義格式化: 使用
set_pattern方法。模式字符含義:%v- 實(shí)際消息文本。%t- 線程ID。%P- 進(jìn)程ID。%n- 日志器名稱。%l- 日志級(jí)別 (短字符:T, D, I, W, E, C)。%L- 日志級(jí)別 (長(zhǎng)字符:TRACE, DEBUG, INFO, WARN, ERROR, CRITICAL)。%a- 縮寫的星期幾。%A- 完整的星期幾。%b,%h- 縮寫的月份。%B- 完整的月份。%c- 日期時(shí)間 (e.g., Thu Aug 23 15:35:46 2018)。%C- 年份 (2位數(shù))。%Y- 年份 (4位數(shù))。%D,%x- 日期 (e.g., 08/23/18)。%T,%X- 時(shí)間 (e.g., 15:35:46)。%r- 12小時(shí)制時(shí)間。%R- 24小時(shí)制時(shí)間 (HH:MM)。%m- 月份 (數(shù)字)。%d- 日 (數(shù)字)。%H- 小時(shí) (24小時(shí)制)。%I- 小時(shí) (12小時(shí)制)。%M- 分鐘。%S- 秒。%e- 毫秒。%f- 微秒。%F- 納秒。%p- AM/PM。%z- UTC偏移 (e.g., +0200)。%Z- 時(shí)區(qū)名稱。%s- 自紀(jì)元以來的秒數(shù)。%g- 自紀(jì)元以來的毫秒數(shù)。%u- 自紀(jì)元以來的微秒數(shù)。%w- 星期幾 (數(shù)字,0=周日)。%j- 一年中的第幾天。%%- 百分號(hào)本身。%^- 開始顏色范圍。%$- 結(jié)束顏色范圍。
日志宏: spdlog 提供了方便的宏,可以自動(dòng)記錄 __FILE__, __LINE__, __func__ 等信息。
#include <spdlog/spdlog.h>
#include <spdlog/fmt/ostr.h> // 對(duì)于自定義類型輸出可能需要
// 基本宏
LOG_TRACE(...);
LOG_DEBUG(...);
LOG_INFO(...);
LOG_WARN(...);
LOG_ERROR(...);
LOG_CRITICAL(...);
// 帶位置信息的宏 (文件名、行號(hào)、函數(shù)名)
SPDLOG_TRACE(...);
SPDLOG_DEBUG(...);
SPDLOG_INFO(...);
SPDLOG_WARN(...);
SPDLOG_ERROR(...);
SPDLOG_CRITICAL(...);
// 示例
int value = 42;
SPDLOG_INFO("The value is {}", value);
SPDLOG_ERROR("Error in function {} at line {}", __func__, __LINE__);- 自定義接收器: 你可以繼承
spdlog::sinks::base_sink類并實(shí)現(xiàn)其sink_it和flush方法,將日志輸出到任何你想要的地方(如數(shù)據(jù)庫(kù)、消息隊(duì)列等)。 - 錯(cuò)誤處理: 可以設(shè)置
logger->set_error_handler([](const std::string &msg) { ... })來處理寫入失敗等錯(cuò)誤。 - 自動(dòng)注冊(cè)與獲?。?/strong> 使用
spdlog::create或spdlog::create_async創(chuàng)建的日志器會(huì)自動(dòng)注冊(cè)到全局注冊(cè)表。之后可以通過spdlog::get("name")獲取。使用spdlog::drop_all()或spdlog::drop("name")釋放資源(特別是異步日志器的后臺(tái)線程)。
5. 性能考量與最佳實(shí)踐
- 評(píng)估是否需要異步: 對(duì)于性能要求極高的應(yīng)用,或者日志量非常大的場(chǎng)景,使用異步日志器。但異步日志器在程序異常退出時(shí)可能會(huì)丟失最后幾條日志(雖然可以通過設(shè)置隊(duì)列大小和刷新策略緩解)。
- 合理設(shè)置日志級(jí)別: 生產(chǎn)環(huán)境通常設(shè)置為
info或warn,開發(fā)調(diào)試時(shí)可用debug或trace。避免在循環(huán)中記錄大量低級(jí)別日志。 - 選擇合適的接收器: 文件寫入通常比控制臺(tái)慢。
rotating_file_sink和daily_file_sink有助于管理日志文件大小和數(shù)量。 - 避免昂貴的操作: 在日志語(yǔ)句中盡量避免執(zhí)行耗時(shí)的操作(如復(fù)雜計(jì)算、IO操作),尤其是在同步日志模式下。可以先判斷日志級(jí)別是否啟用
if (logger->should_log(spdlog::level::debug)) { ... }。 - 注意格式化開銷: 復(fù)雜的格式化字符串或大量參數(shù)也會(huì)帶來開銷。
6. 編譯與依賴
- 依賴:
spdlog是一個(gè)頭文件庫(kù)(header-only),但需要依賴一個(gè)C++11兼容的編譯器和一個(gè)格式化庫(kù)(默認(rèn)使用其內(nèi)置的fmt庫(kù)分支)。因此,通常只需要包含頭文件即可使用。 - 編譯選項(xiàng): 可以通過定義宏來控制
spdlog的行為:SPDLOG_COMPILED_LIB: 將其編譯為靜態(tài)庫(kù)(需要包含spdlog.cpp)。SPDLOG_FMT_EXTERNAL: 使用外部的fmt庫(kù)(需確保已安裝)而不是spdlog內(nèi)置的版本。SPDLOG_NO_EXCEPTIONS: 禁用異常(在異常被禁用的環(huán)境中使用)。SPDLOG_NO_THREAD_ID: 禁用線程ID記錄(如果獲取線程ID開銷大)。SPDLOG_CLOCK_COARSE: 使用更快的coarse時(shí)鐘源(精度較低)。
- 安裝: 可以通過包管理器(如vcpkg, conan)、Git子模塊或直接下載源碼放入項(xiàng)目目錄。
7. 總結(jié)
spdlog 是一個(gè)強(qiáng)大、高效且靈活的C++日志庫(kù),幾乎能滿足所有常見的日志記錄需求。其簡(jiǎn)潔的API、出色的性能表現(xiàn)(尤其是異步模式)以及豐富的功能(多接收器、自定義格式、多級(jí)別)使其成為C++項(xiàng)目中日志組件的優(yōu)秀選擇。無論是快速原型開發(fā)還是大型高性能應(yīng)用,spdlog 都值得考慮。
二、庫(kù)的下載與編譯
參考我這篇博文:C++ spdlog日志庫(kù)編譯與安裝詳解
三、示例
1、測(cè)試代碼
以下是一個(gè)較為復(fù)雜的C++ spdlog日志庫(kù)使用示例,包含多線程、異步日志、多接收器(sink)和自定義格式設(shè)置:
#include <spdlog/spdlog.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/async.h>
#include <thread>
#include <iostream>
int main() {
try {
// 創(chuàng)建異步日志線程池(隊(duì)列大小1024,線程數(shù)1)
spdlog::init_thread_pool(1024, 1);
// 創(chuàng)建文件接收器(每天輪轉(zhuǎn),最大3個(gè)文件,單個(gè)文件最大50MB)
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
"logs/mylog.log", 50 * 1024 * 1024, 3
);
file_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%t] %v");
// 創(chuàng)建控制臺(tái)彩色輸出接收器
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
console_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v");
// 創(chuàng)建異步日志器(組合兩個(gè)接收器)
std::vector<spdlog::sink_ptr> sinks{file_sink, console_sink};
auto async_logger = std::make_shared<spdlog::async_logger>(
"async_logger", sinks.begin(), sinks.end(), spdlog::thread_pool()
);
async_logger->set_level(spdlog::level::trace); // 設(shè)置日志級(jí)別
// 注冊(cè)全局日志器
spdlog::register_logger(async_logger);
spdlog::set_default_logger(async_logger);
// 自定義錯(cuò)誤處理
spdlog::flush_every(std::chrono::seconds(3)); // 每3秒刷新到磁盤
spdlog::set_error_handler([](const std::string& msg) {
std::cerr << "Log error: " << msg << std::endl;
});
// 多線程日志測(cè)試
auto log_func = []() {
for (int i = 0; i < 100; ++i) {
SPDLOG_TRACE("Trace message {}", i);
SPDLOG_DEBUG("Debug message {}", i);
SPDLOG_INFO("Info message {}", i);
SPDLOG_WARN("Warning message {}", i);
SPDLOG_ERROR("Error message {}", i);
SPDLOG_CRITICAL("Critical message {}", i);
}
};
std::thread t1(log_func);
std::thread t2(log_func);
t1.join();
t2.join();
// 顯式刷新確保所有日志寫入
spdlog::shutdown();
} catch (const spdlog::spdlog_ex& ex) {
std::cerr << "Log exception: " << ex.what() << std::endl;
}
return 0;
}2、運(yùn)行結(jié)果



3、功能說明:
- 多接收器配置:
- 文件接收器:帶輪轉(zhuǎn)功能(每天/按大小)
- 控制臺(tái)接收器:帶彩色級(jí)別顯示
- 異步日志:
- 使用線程池處理日志寫入
- 避免阻塞主線程
- 自定義格式:
- 時(shí)間格式:
%Y-%m-%d %H:%M:%S.%e - 包含線程ID:
%t - 級(jí)別高亮:
%^%l%$
- 時(shí)間格式:
- 多線程支持:
- 兩個(gè)線程同時(shí)寫入日志
- 線程安全保證
- 異常處理:
- 自定義錯(cuò)誤回調(diào)
- 全局異常捕獲
- 性能優(yōu)化:
- 定期刷新(
flush_every) - 隊(duì)列大小控制
- 定期刷新(
到此這篇關(guān)于C++ spdlog日志庫(kù)詳解的文章就介紹到這了,更多相關(guān)C++ spdlog日志庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VC++獲得當(dāng)前進(jìn)程運(yùn)行目錄的方法
這篇文章主要介紹了VC++獲得當(dāng)前進(jìn)程運(yùn)行目錄的方法,可通過系統(tǒng)函數(shù)實(shí)現(xiàn)該功能,是非常實(shí)用的技巧,需要的朋友可以參考下2014-10-10
C++實(shí)現(xiàn)對(duì)RGB圖片進(jìn)行編碼的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用得到的RGB信息重新對(duì)RGB圖片進(jìn)行編碼,以及對(duì)其他圖片如BMP所得到的RGB信息進(jìn)行編碼從而得到*.jpg文件,感興趣的可以了解一下2023-05-05
C++?折疊參數(shù)包詳解(悄然增強(qiáng)編程效率)
折疊參數(shù)就是一個(gè)參數(shù)包, 代表是多個(gè)未知,tuple元組就是一個(gè)折疊參數(shù)的使用,這篇文章主要介紹了C++?折疊參數(shù)包悄然增強(qiáng)編程效率,需要的朋友可以參考下2023-05-05
C語(yǔ)言 語(yǔ)義陷阱超詳細(xì)梳理總結(jié)
這篇文章主要介紹了C語(yǔ)言常見的一些語(yǔ)義陷阱,梳理的比較全面,對(duì)我們做開發(fā)的過程中有一定幫助,感興趣的朋友快來看看吧2022-03-03
詳解C++內(nèi)存的代碼區(qū),全局區(qū),棧區(qū)和堆區(qū)
這篇文章主要為大家介紹了C++內(nèi)存的代碼區(qū),全局區(qū),棧區(qū)和堆區(qū),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2021-12-12

