[TOC] spdlog是一個開源、跨平臺、無依賴、只有頭文件的C++11日誌庫,網上介紹的文章有很多這裡就不過多的介紹了,GitHub鏈接:[https://github.com/gabime/spdlog](https://github.com/gabime/spdlog)。 # 引用源碼 先下 ...
目錄
spdlog是一個開源、跨平臺、無依賴、只有頭文件的C++11日誌庫,網上介紹的文章有很多這裡就不過多的介紹了,GitHub鏈接:https://github.com/gabime/spdlog。
引用源碼
先下載spdlog的源碼,將源碼的include文件夾複製到自己的項目文件夾下:
然後在項目屬性中包含include目錄,如下圖所示:
封裝Log頭文件
一般的項目對日誌要求都不高,主要是要求日誌線程安全、非同步寫入文件、每天生成新日誌、支持日誌回調顯示,spdlog稍微配置一下即可。
把spdlog相關的配置全放到Log.h文件中,封裝成Log頭文件有兩個好處:
- 可以隨時替換後臺日誌實現
- 對外只用暴露一個頭文件
Log頭文件的代碼如下:
#pragma once
#include "spdlog/spdlog.h"
#include "spdlog/async.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/stopwatch.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/callback_sink.h"
#include <iostream>
void init_spdlog()
{
//非同步日誌,具有8k個項目和1個後臺線程的隊列
spdlog::init_thread_pool(8192, 1);
//標準控制台輸出
auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt >();
stdout_sink->set_level(spdlog::level::debug);
//日誌文件輸出,0點0分創建新日誌
auto file_sink = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/log.txt", 0, 0);
file_sink->set_level(spdlog::level::info);
//日誌回調
auto callback_sink = std::make_shared<spdlog::sinks::callback_sink_mt>([](const spdlog::details::log_msg& msg)
{
//日誌記錄器名稱
std::string name(msg.logger_name.data(), 0, msg.logger_name.size());
//日誌消息
std::string str(msg.payload.data(), 0, msg.payload.size());
//日誌時間
std::time_t now_c = std::chrono::system_clock::to_time_t(msg.time);
//回調的處理邏輯自己根據項目情況定義,比如實時顯示到UI、保存到資料庫等等
//.... 回調處理邏輯的示例
//std::tm localTime;
//localtime_s(&localTime, &now_c);
//char timeStr[50];
//std::strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", &localTime);
//// 獲取毫秒數
//auto duration = msg.time.time_since_epoch();
//auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;
//std::cout << timeStr << "." << std::setfill('0') << std::setw(3) << milliseconds << " " ;
//std::cout << to_string_view(msg.level).data() << " " << str << std::endl << std::endl << std::flush;
});
callback_sink->set_level(spdlog::level::info);
std::vector<spdlog::sink_ptr> sinks{ stdout_sink, file_sink,callback_sink };
auto log = std::make_shared<spdlog::async_logger>("logger", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);
//設置日誌記錄級別,您需要用 %^ 和 %$ 括上想要彩色的部分
log->set_level(spdlog::level::trace);
//設置格式
//參考 https://github.com/gabime/spdlog/wiki/3.-Custom-formatting
//[%Y-%m-%d %H:%M:%S.%e] 時間
//[%l] 日誌級別
//[%t] 線程
//[%s] 文件
//[%#] 行號
//[%!] 函數
//[%v] 實際文本
log->set_pattern("[%Y-%m-%d %H:%M:%S.%e] %^[%l]%$ [%t] [%s %!:%#] %v");
//設置當出發 err 或更嚴重的錯誤時立刻刷新日誌到 disk
log->flush_on(spdlog::level::err);
//3秒刷新一次隊列
spdlog::flush_every(std::chrono::seconds(3));
spdlog::set_default_logger(log);
}
//單個日誌記錄器
std::shared_ptr<spdlog::logger> get_async_file_logger(std::string name)
{
auto log = spdlog::get(name);
if (!log)
{
//指針為空,則創建日誌記錄器,
log = spdlog::daily_logger_mt<spdlog::async_factory>(name, "logs/" + name + "/log.txt");
log->set_level(spdlog::level::trace);
log->flush_on(spdlog::level::err);
log->set_pattern("[%Y-%m-%d %H:%M:%S.%e] %^[%l]%$ [%t] [%s %!:%#] %v");
//記錄器是自動註冊的,不需要手動註冊 spdlog::register_logger(name);
}
return log;
}
#define INITLOG() init_spdlog()
#define TRACE(...) SPDLOG_TRACE(__VA_ARGS__)
#define DEBUG(...) SPDLOG_DEBUG(__VA_ARGS__)
#define INFO(...) SPDLOG_INFO(__VA_ARGS__)
#define WARN(...) SPDLOG_WARN(__VA_ARGS__)
#define ERROR(...) SPDLOG_ERROR(__VA_ARGS__)
#define CRITICAL(...) SPDLOG_CRITICAL(__VA_ARGS__)
//單個日誌文件
#define GETLOG(LOG_NAME) get_async_file_logger(LOG_NAME)
#define LOGGER_TRACE(logger,...) SPDLOG_LOGGER_TRACE(logger,__VA_ARGS__)
#define LOGGER_DEBUG(logger,...) SPDLOG_LOGGER_DEBUG(logger,__VA_ARGS__)
#define LOGGER_INFO(logger,...) SPDLOG_LOGGER_INFO(logger,__VA_ARGS__)
#define LOGGER_WARN(logger,...) SPDLOG_LOGGER_WARN(logger,__VA_ARGS__)
#define LOGGER_ERROR(logger,...) SPDLOG_LOGGER_ERROR(logger,__VA_ARGS__)
#define LOGGER_CRITICAL(logger,...) SPDLOG_LOGGER_CRITICAL(logger,__VA_ARGS__)
//時間統計巨集
#define LOGSW() spdlog::stopwatch()
上面的代碼是用於初始化和配置spdlog庫的日誌記錄器的代碼。主要包括以下幾個部分:
- init_spdlog()函數用於初始化spdlog庫的配置。該函數創建了一個包含控制台、文件和回調三種sink的日誌記錄器,並設置將其設置為預設記錄器。
- get_async_file_logger()函數獲取一個單獨的非同步文件日誌記錄器,主要用於記錄多線程日誌,一般情況下用的比較少。
- 用於簡化日誌記錄的操作一些巨集,spdlog自帶的有日誌巨集,這裡只是簡化一下並做隔離,實際上是對spdlog庫的相應函數進行了封裝。
- 定義了一個LOGSW()巨集,用於方便地創建一個時間統計器,使用時不需要過多的關註統計類本身。
使用方法
使用方法如下:
#include "Log.h"
#include <thread>
#include <chrono>
#include <iostream>
int main()
{
INITLOG("path");
//單個日誌
auto log1= GETLOG("Test1");
auto log2= GETLOG("Test1");
//原始調用方式
//SPDLOG_LOGGER_INFO(log1, "123");
LOGGER_INFO(log2, "123");
auto sw = LOGSW();
// 延時2秒
std::this_thread::sleep_for(std::chrono::seconds(2));
INFO("Elapsed {0} {1}","時間", sw);
WARN("Elapsed {0} {1}", "時間", sw);
//原始調用方式
//SPDLOG_INFO("TEST");
INFO("TEST");
}
最後生成的日誌文件如下: