前言
鉴于工作需求,日志记录工具是必不可少的存在。
现对 spdlog 在c++项目的使用方法进行探究。
项目地址
https://github.com/gabime/spdlog#compiled-version-recommended---much-faster-compile-times
官方说明文档地址
https://github.com/gabime/spdlog/wiki
使用方法
将项目源码中的 inlcude 中的 spdlog 文件夹添加到自己的项目中即可使用。
该项目通过 logger 作为对象进行调用,logger 接受用户的日志信息,对应日志的输入端,然后传递给 sink,sink对应日志的输出端。
所以通过建立多个 sink 对应一个 logger 就可以实现同日志输入但是输出多个不同等级要求的日志文件。
完整Demo
main文件初始化日志代码:
#include "mainwindow.h"
#include <QApplication>
#include <QSettings>
#include <QDir>
#include <QDebug>
#include "log4z/log4z.h"
#include "spdlog/spdlog.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h" // or "../stdout_sinks.h" if no colors needed
void initSPDLOG(){
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
console_sink->set_level(spdlog::level::warn);
auto file_sink_trace = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/Trace/Trace.log", 23, 59, false);
file_sink_trace->set_level(spdlog::level::trace);
auto file_sink_debug = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/debug/debug.log", 23, 59, false, 0);
file_sink_debug->set_level(spdlog::level::debug);
auto file_sink_info = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/Info/Info.log", 23, 59, false, 0);
file_sink_info->set_level(spdlog::level::info);
auto file_sink_warn = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/warn/warn.log", 23, 59, false, 0);
file_sink_warn->set_level(spdlog::level::warn);
auto file_sink_err = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/err/err.log", 23, 59, false, 0);
file_sink_err->set_level(spdlog::level::err);
auto file_sink_critical = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/critical/critical.log", 23, 59, false, 0);
file_sink_critical->set_level(spdlog::level::critical);
// 组合sink列表
spdlog::sinks_init_list sink_list = { console_sink, file_sink_trace, file_sink_debug, file_sink_info, file_sink_warn,
file_sink_err, file_sink_critical};
// 将sink列表设置到全局
spdlog::set_default_logger(std::make_shared<spdlog::logger>("multi_sink", sink_list));
// 设置日志内容输出格式
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] %^[%l]%$ %v");
// spdlog 默认level为 INfo 需要手动改 trace
spdlog::set_level(spdlog::level::trace);
// 设置刷新,刷新本地文件,以便随时查看本地日志文件
spdlog::flush_every(std::chrono::seconds(5));
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
AllocConsole();
freopen("CONOUT$", "a+", stdout);
// psdLog
initSPDLOG();
MainWindow w;
w.show();
return a.exec();
}
全局使用方法:
int myMesg = 1;
QString testMesg = "hello word";
spdlog::trace("trace message {} {}", myMesg, testMesg.toStdString().c_str());
spdlog::debug("debug message");
spdlog::info("info message");
spdlog::warn("waring message");
spdlog::error("error message");
spdlog::critical("critical message");
如需要添加新的输出 sink,如 qt 控件。
auto qt_sink_trace = std::make_shared<spdlog::sinks::qt_sink_mt>(ui->plainTextEdit, "appendPlainText");
qt_sink_trace->set_level(spdlog::level::trace);
spdlog::get("multi_sink")->sinks().push_back(qt_sink_trace);
记下来对代码内容进行说明
新建 sink
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h" // or "../stdout_sinks.h" if no colors needed
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
console_sink->set_level(spdlog::level::warn);
auto file_sink_trace = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logs/Trace/Trace.log", 23, 59, false);
file_sink_trace->set_level(spdlog::level::trace);
sink 作为日志的输出,有很多种。 常用如下,其余可参考说明文档。
| 类名 | 特性 |
|---|---|
| rotating_file_sink | 可根据设定的大小自动分开日志文件 |
| daily_file_sink | 可根据设定的日期自动分开日志文件 |
| simple_file_sink | 固定一个文件 |
| stdout_color_sink | 标准输出 |
代码中使用时需要添加对应 sink 头文件。
不同 sink 需要的构造参数不同,可参考对应构造函数。
其中 truncate 设定 false 表示如果存在同名日志,在其后继续记录,否则清空从头开始记录。
每一个 sink 构造时分为 mt 和 st,根据官方文档说明 mt 表示 multithrad,st 表示 singlethread。
为了线程安全只用 mt 就好,st 特殊需求可能会用到。
新建 logger
// 组合sink列表
spdlog::sinks_init_list sink_list = { console_sink, file_sink_trace, file_sink_debug, file_sink_info, file_sink_warn,
file_sink_err, file_sink_critical};
通过 sinks_init_list 将所有建立的 sink 放到一个列表里,变量名为 sink_list。
// 将sink列表设置到全局
spdlog::set_default_logger(std::make_shared<spdlog::logger>("multi_sink", sink_list));
这段代码有两层意思,组合到了一起。
先通过 make_shared 建造了一个标准 logger,将 sink_list 作为构造参数传入,获得一个 logger,变量名为 multi_sink, 再通过 spdlog::set_dafult_logger 将刚刚创建的 multi_sink 设定为全局 logger。
这样在别的任意地方调用默认打印日志的方法就会调用 multi_sink 这个 logger。
// 设置日志内容输出格式
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] %^[%l]%$ %v");
设定全局的日志输出格式。
如果有不同 sink 不同格式的需求,可以直接给单个 sink 进行设置。
设置方法详见说明文档。
// spdlog 默认level为 INfo 需要手动改 trace
spdlog::set_level(spdlog::level::trace);
spdlog 默认全局 level 为 INFO,如果不设置的话 debug 和 trace 的信息将无法输出。
// 设置刷新,刷新本地文件,以便随时查看本地日志文件
spdlog::flush_every(std::chrono::seconds(5));
不设置这个的话调试窗口的日志也能正常输出,但是本地文件流只有在程序关闭的时候才会全部写入。
通过设定5s刷新,就能随时查看本地文件的日志了。
全局输出日志
#include "spdlog/spdlog.h"
int myMesg = 1;
QString testMesg = "hello word";
spdlog::trace("trace message {} {}", myMesg, testMesg.toStdString().c_str());
spdlog::debug("debug message");
spdlog::info("info message");
spdlog::warn("waring message");
spdlog::error("error message");
spdlog::critical("critical message");
在需要打印日志的地方引入头文件,然后直接进行全局日志输出方法调用。
需要传参就通过 {} 类python的写法,很方便。