首页 > 分享 > C++ 好用的日志库

C++ 好用的日志库

背景

spdlog 是一个快速、异步的、header-only 的 C++ 日志库。它提供了简单易用的 API 并具有高性能和可扩展性。

下载和使用

下载

spdlog 库下载地址:github 链接

hello world

在使用时只需要 include 整个 /include/spdlog 文件夹即可。

#include "spdlog/spdlog.h" int main() { spdlog::info("hello world"); return 0; }

运行结果如下:

如上图所示,spdlog 库上手非常简单。

基本概念

核心组件

spdlog 有以下基本组成部分:

Registry(日志记录器注册表):Registry 用于管理所有已创建的 Logger 对象。 Logger(日志记录器):Logger 是打印日志的核心对象,负责记录日志消息。可以根据需要创建多个Logger 对象。 Sink(日志输出):Sink 是 Logger 的目标输出位置,它指定了日志消息的最终存储位置。每个 Logger 内包含一个 Sink 组成的 vector。 Formatter(日志格式化):Formatter 用于格式化日志消息的输出格式。

通过以上组件,可以灵活地配置和使用 spdlog,以满足不同的日志需求。例如,可以创建多个 Logger 对象,并将它们的日志消息输出到不同的文件中;也可以自定义日志消息的格式,添加时间戳和其他元数据。

日志格式

spdlog 自带了默认的 formatter,其格式为:[日期时间] [logger名] [log级别] log内容。

日志级别

spdlog 提供了一组日志级别,用于控制记录哪些级别的日志消息:

trace:最详细的日志级别,提供追踪程序执行流程的信息。 debug:调试级别的日志信息,用于调试程序逻辑和查找问题。 info:通知级别的日志信息,提供程序运行时的一般信息。 warn:警告级别的日志信息,表明可能发生错误或不符合预期的情况。 error:错误级别的日志信息,表明发生了某些错误或异常情况。 critical:严重错误级别的日志信息,表示一个致命的或不可恢复的错误。
通过设置日志记录器的级别,可以控制哪些级别的日志进行输出:

#include "spdlog/sinks/stdout_color_sinks.h" int main() { auto logger = spdlog::stdout_color_mt("console"); logger->set_level(spdlog::level::warn); logger->trace("trace message"); logger->debug("debug message"); logger->info("info message"); logger->warn("warn message"); logger->error("error message"); logger->critical("critical message"); return 0; }

运行结果如下:

日志参数

spdlog 绑定了 fmt 库,可以用于格式化输出日志内容:

#include "spdlog/sinks/stdout_color_sinks.h" int main() { auto logger = spdlog::stdout_color_mt("console"); logger->info("log message {},{}","hello",123); return 0; }

运行结果如下:

spdlog 快速上手

概述

spdlog 提供了一系列工厂函数用于创建 Logger。其中以 _mt 后缀的表示创建多线程的日志记录器、以 -st 后缀的表示创建单线程的日志记录器。

创建控制台 Logger

#include "spdlog/spdlog.h" #include "spdlog/sinks/stdout_color_sinks.h" int main() { auto logger = spdlog::stdout_color_mt("console"); logger->info("hello world"); return 0; }

运行结果如下:

创建基本文件 Logger

#include "spdlog/spdlog.h" #include "spdlog/sinks/basic_file_sink.h" int main() { auto logger = spdlog::basic_logger_mt("file","my_log.log"); logger->info("hello world"); return 0; }

运行结果如下:

创建滚动文件 Logger

可以设置日志文件的大小及数量限定:

#include "spdlog/spdlog.h" #include "spdlog/sinks/rotating_file_sink.h" int main() { auto max_size = 1024*2;// 每个文件最大 2 k auto max_files = 3;//最多滚动 3 次 auto logger = spdlog::rotating_logger_mt("file","my_log.log", max_size, max_files); for( int i = 0 ;i < 100;++i) { logger->info("rotating file log test"); } return 0; }

运行结果如下:

创建每日 Logger

可以在每天固定时间点创建一个新的日志文件:

#include "spdlog/spdlog.h" #include "spdlog/sinks/daily_file_sink.h" int main() { auto logger = spdlog::daily_logger_mt("daily_logger", "my_log.log", 0, 0); return 0; }

创建异步日志

可以与 spdlog::async_factory 搭配使用,以实现异步日志。异步记录可以提高程序的性能,因为日志写入操作不会阻塞主线程。

#include "spdlog/async.h" #include "spdlog/sinks/stdout_color_sinks.h" int main() { auto logger = spdlog::stdout_color_mt<spdlog::async_factory>("async_logger"); logger->info("123"); return 0; }

运行结果如下:

创建 Logger

spdlog 提供的工厂方法封装了 sink 的创建过程,也可以根据需要先创建 sink ,再创建 Logger。

创建 Sink

sink 是将日志实际写入其目标(文件、控制台、数据库等)的对象,且应仅负责单个目标。

创建控制台 sink

auto sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); 创建文件 sink

auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("my_log.log"); 创建每日文件 sink

auto sink = std::make_shared<spdlog::sinks::daily_file_sink_mt>("my_log.log",23,59); 创建滚动文件 sink

auto sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("my_log.log",1048576 * 5, 3,false); 创建流输出 sink

std::ostringstream oss; auto ostream_sink = std::make_shared<spdlog::sinks::ostream_sink_mt> (oss);

根据 sink 创建 Logger

创建单 sink 记录器

可以直接在构造函数中传入 sink 来创建 Logger:

int main() { auto sink = std::make_shared<spdlog::sinks::stderr_color_sink_mt>(); auto logger = std::make_shared<spdlog::logger>("my_logger", sink); logger->info("hello world "); return 0; } 创建多 sink 记录器

也可以传入一个 sink 列表来创建 Logger,每个 sink 可单独设置日志级别和样式:

int main() { auto sink1 = std::make_shared<spdlog::sinks::stderr_color_sink_mt>(); auto sink2 = std::make_shared<spdlog::sinks::basic_file_sink_mt>("my_log.log"); spdlog::sinks_init_list sinks = { sink1,sink2}; auto logger = std::make_shared<spdlog::logger>("my_logger", sinks.begin(),sinks.end()); logger->info("hello world "); return 0; } 创建共用 sink 记录器

多个 Logger 也可以共用相同的 sink :

int main() { auto sink = std::make_shared<spdlog::sinks::stderr_color_sink_mt>(); auto logger1 = std::make_shared<spdlog::logger>("logger1", sink); auto logger2 = std::make_shared<spdlog::logger>("logger2", sink); auto logger3 = std::make_shared<spdlog::logger>("logger3", sink); logger1->info("hello world "); logger2->info("hello world "); logger3->info("hello world "); return 0; }

Logger 注册与获取

spdlog 提供了一个全局注册和获取 logger 的方法。

Logger 注册

使用 spdlog 工厂方法创建的 logger 无需手动注册即可根据名称获取,手动创建的 logger 需要注册。

#include "spdlog/sinks/stdout_color_sinks.h" #include <spdlog/spdlog.h> void register_logger() { auto sink = std::make_shared<spdlog::sinks::stderr_color_sink_mt>(); auto logger = std::make_shared<spdlog::logger>("my_logger", sink); spdlog::register_logger(logger); } int main() { register_logger(); auto logger = spdlog::get("my_logger"); logger->info("hello world"); return 0; } Logger 删除

手动注册的全局 logger 也可以删除:

spdlog::drop("my_logger");//全局注册中删除指定 logger spdlog::drop_all();// 删除所有注册的 logger

Logger 的使用与设置

设置默认 Logger

spdlog 提供了最为便捷的默认 logger,注意,该logger在全局公用:

spdlog::info("hello world");

可以设置自定义的 logger 为全局默认:

auto logger = spdlog::stdout_color_mt("my_log"); spdlog::set_default_logger(logger);

设置日志级别

logger 和 sink 都可以单独指定日志级别。

设置指定 Logger 级别

auto logger = spdlog::stdout_color_mt("my_log"); logger->set_level(spdlog::level::debug); 设置指定 sink 级别

auto sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); sink->set_level(spdlog::level::debug); 设置默认 Logger 级别

spdlog::set_level(spdlog::level::debug);

设置缓存刷新策略

创建好 Logger 后建议设置 flush 方式,否则可能无法立刻在文件中看到 logger 的内容:

定时刷新

spdlog::flush_every(std::chrono::seconds(5));// 定期为所有注册的logger隔5秒刷新 基于级别刷新

auto logger = spdlog::stdout_color_mt("my_log"); logger->flush_on(spdlog::level::warn);//遇到 warn 就立即刷新 手动刷新

auto logger = spdlog::stdout_color_mt("my_log"); logger->flush()// logger 将依次在每个 sink 上调用 flush

spdlog 使用进阶

记录自定义类型

用户自定义类型对象作为日志参数进行记录,需要重置输出运算符:

#include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/fmt/ostr.h" class demo{ public: demo(int id_,const std::string &name_):id(id_),name(name_){ } private: int id ; std::string name; public: friend std::ostream& operator<<(std::ostream& os, const demo& d); }; std::ostream &operator<<(std::ostream &os, const demo &d) { os << "id:"<<d.id<<", name:"<<d.name<<std::endl; return os; } int main() { demo d(10,"demo_1"); auto logger = spdlog::stdout_color_mt("console"); logger->info("log message {}",d); return 0; }

运行结果如下:

记录 vector 中数据

vector 对象可以直接作为参数进行输出:

#include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/fmt/ranges.h" int main() { auto logger = spdlog::stdout_color_mt("console"); std::vector<int> vec{ 1,2,3,4,5}; logger->info("vector data :{}",vec); return 0; }

运行结果如下:

记录运行时间

使用 spdlog::stopwatch 对象可以记录代码运行时间:

#include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/stopwatch.h" #include <thread> void test() { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } int main() { auto logger = spdlog::stdout_color_mt("console"); spdlog::stopwatch sw; test(); logger->info("test run {} seconds",sw); return 0; }

运行结果如下:

记录十六进制数据

使用 to_hex 可以吧二进制数据转十六进制进行记录:

#include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/fmt/bin_to_hex.h" int main() { auto logger = spdlog::stdout_color_mt("console"); unsigned char data[] = { 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56}; logger->info("Hex string: {} ", spdlog::to_hex(std::begin(data), std::begin(data)+sizeof(data))); return 0; }

运行结果如下:

还可以显示对应 ASCII 值:

int main() { auto logger = spdlog::stdout_color_mt("console"); unsigned char data[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66}; logger->info("Hex string: {:a} ", spdlog::to_hex(std::begin(data), std::begin(data)+sizeof(data),4)); return 0; }

运行结果如下:

记录文件名及行号

在使用 spdlog 记录日志时,可以通过格式化字符串来包含方法名、行号和文件名的信息:

#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE #include <spdlog/spdlog.h> #include "spdlog/sinks/stdout_color_sinks.h" int main() { spdlog::set_pattern("[%H:%M:%S] [%n] [%^---%L---%$] [%s:%#] [%!] %v"); auto logger = spdlog::stdout_color_mt("my_log"); SPDLOG_LOGGER_INFO(logger, "This is a log message"); return 0; }

运行结果如下:

一定确保 SPDLOG_ACTIVE_LEVEL 定义的日志级别低于或等于你期望的日志级别,并且在包含 spdlog.h 之前定义了它。

其他特殊 Logger

qt sink

qt_sink 可以向 QTextBrowser、QTextEdit 等控件输出日志消息:

#include "spdlog/sinks/qt_sinks.h" auto logger = spdlog::qt_logger_mt("QLogger",ui->textBrowser); logger->info("hello QTextBrowser"); logger->warn("this msg from spdlog");

运行结果如下:

msvc sink

msvc_sink 使用 OutputDebugStringA 向 Windows调试接收器发生日志记录:

#include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/sinks/msvc_sink.h" int main() { auto sink = std::make_shared<spdlog::sinks::msvc_sink_mt>(); auto logger = std::make_shared<spdlog::logger>("msvc_logger", sink); logger->info("debug log test..."); return 0; }

运行结果如下:

消息过滤 sink

dup_filter_sink 可以实现重复消息删除:

#include "spdlog/sinks/stdout_color_sinks.h" #include "spdlog/sinks/dup_filter_sink.h" int main() { auto sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); auto dup_filter_sink= std::make_shared<spdlog::sinks::dup_filter_sink_mt>(std::chrono::seconds(5)); dup_filter_sink->add_sink(sink); auto logger = std::make_shared<spdlog::logger>("msvc_logger", dup_filter_sink); logger->info("hello world"); logger->info("hello world"); logger->info("hello world"); logger->info("hello world"); logger->info("log msg"); return 0; }

运行结果如下:

ringbuffer sink

ringbuffer_sink 将最新的日志消息保存在内存中:

#include <spdlog/spdlog.h> #include "spdlog/sinks/ringbuffer_sink.h" #include "spdlog/fmt/ranges.h" int main() { auto ringbuffer_sink = std::make_shared<spdlog::sinks::ringbuffer_sink_mt>(5); auto logger = std::make_shared<spdlog::logger>("ringbuffer_logger", ringbuffer_sink); for (int i = 0; i < 20; ++i) { logger->info("Log message {}", i); } std::vector<std::string> log_messages = ringbuffer_sink->last_formatted(1); spdlog::info("{}",log_messages); return 0; }

运行结果如下:

udp sink

spdlog 提供的一个封装了 UDP 传输的 logger。它可以将日志记录通过 UDP 协议发送到指定的目标地址和端口:

#include <spdlog/spdlog.h> #include "spdlog/sinks/udp_sink.h" int main() { spdlog::sinks::udp_sink_config cfg("127.0.0.1", 11091); auto my_logger = spdlog::udp_logger_mt("udplog", cfg); my_logger->info("hello world"); return 0; }

支持回调的 Logger

callback_logger_mt 是一个支持设置调用回调函数的日志记录器:

#include <spdlog/spdlog.h> #include <iostream> #include "spdlog/sinks/callback_sink.h" int main() { auto logger = spdlog::callback_logger_mt("custom_callback_logger", [](const spdlog::details::log_msg & msg) { std::cout << msg.payload.data() << std::endl; }); logger->info("123"); return 0; }

运行结果如下:

相关知识

a=b++,c++和a=(b++,c++)的区别
C++中+= 是什么意思
大模型训练:高效保存与解析日志的策略
Python 日志教程
如何在 Java 中进行日志记录
日志记录 HOWTO — Python 文档
C++程序设计(上)练习
C++第二天
大模型训练:便捷保存日志的策略与方法
C++动物运动会源代码资源

网址: C++ 好用的日志库 https://m.mcbbbk.com/newsview419844.html

所属分类:萌宠日常
上一篇: Docker 日志记录
下一篇: 在 Spring Boot 中使