C++高性能日志库spdlog
spdlog简介
spdlog 是一个高性能的 C++ 日志库,它设计时充分考虑了速度和易用性,具有以下特点
-
高效与快速:Spdlog 专注于提供极致的性能,在大量日志记录场景下也能保持较低的延迟和较高的吞吐量。
-
低内存占用:Spdlog的设计确保了即使在高负载下,它也能保持低内存占用。
-
轻量化设计:Spdlog 是头文件(header-only)库,这意味着用户只需要包含相应的头文件即可开始使用,无需编译链接额外的库文件。
-
跨平台支持:它支持多种操作系统,包括但不限于 Windows、Linux 和 macOS,并且在这些平台上都能够良好运行。
-
丰富的日志级别:Spdlog 支持常见的日志级别,如 TRACE、DEBUG、INFO、WARN、ERROR、CRITICAL 等,用户可以根据需要选择不同级别的日志输出。
-
格式化与定位信息:通过集成 fmt 库,Spdlog 允许用户自定义日志消息的格式,可以轻松地包含时间戳、线程ID、文件名、行号以及函数名等上下文信息。
-
多目标输出:可以将日志输出到控制台、普通文本文件、循环写入文件(rotating log files)、每日生成新文件(daily logs)、系统日志等目标,同时也支持异步写入以提高性能。
-
线程安全:对于多线程环境,Spdlog 提供了线程安全的日志接口,确保在并发环境下日志记录的正确性和完整性。
-
异步模式:提供可选的异步日志记录机制,能够将日志操作放入后台线程执行,从而避免阻塞主线程。
-
条件日志:根据预定义的条件开关,可以动态启用或禁用特定级别的日志输出。
Spdlog下载
# 项目下载
git clone https://github.com/gabime/spdlog.git
#编译
cd spdlog
mkdir build
cd build
cmake ..
make -j
#安装
sudo make install#或者直接下载
sudo apt-get install libspdlog-dev
Spdlog日志
1.日志的作用
- 问题排查与故障诊断
- 数据备份与恢复
- 系统监控与性能优化
- 安全审计与合规性检查
2.同步和异步的区别
执行方式:
同步:在同步日志记录中,应用程序在执行日志记录操作时,会暂停当前的业务流程,直到日志被成功写入到存储介质(如文件、数据库等)中。
异步:而异步日志则是将日志记录操作放在一个单独的线程或队列中进行处理。当应用程序需要记录日志时,它只是将日志信息发送到一个缓冲区或队列中,然后继续执行后续的业务逻辑。
性能:
同步:由于同步日志会阻塞当前线程,等待日志写入完成,因此在高并发场景下,如果日志记录操作较为频繁,可能会导致业务线程的阻塞,从而影响整个应用程序的性能和响应时间。
异步:异步日志由于不会阻塞业务线程,所以可以提高应用程序的性能和响应速度。在高并发情况下,它能够将日志记录的开销分散到后台线程,使得业务逻辑能够更快速地执。
3.Spdlog为什么高效
- 零成本抽象:spdlog通过模板和内联函数来实现零成本抽象,确保只有在真正需要时才进行日志记录。
- 异步日志记录:spdlog支持异步日志记录,这意味着它可以将日志信息发送到线程池进行处理,从而减少了对主线程性能的影响。
- 高效地格式化:spdlog使用fmt库进行高效的字符串格式化,减少了格式化日志信息所需要的事件。
4.Spdlog处理流程
Loggers负责记录日志信息,Sinks决定了日志消息的输出位置,Formatters负责将日志信息转换为特定格式,AsyncLoffer异步地将日志消息写入到目标Sink中,Registry用于管理这些组件。
5. 相关问题
1.多线程使用日志库,跟同步和异步是否有关联
没有什么关联
2.同一个线程处理的,是不是就是同步的
如果时当前处理程序处理的那就是同步,如果仅仅是获得完成通知,那就只是协程上的同步
3.为什么需要这么多的日志级别
trece,debug,info,warn,error,critical
从左到右,级别越来越高
级别 | 用途描述 |
---|---|
trace | 最细节的日志,追踪变量,执行路径,性能分析时有用(函数级别打印) |
debug | 调试信息,用于开发器观察程序逻辑,如状态变化(模块级别状态) |
info | 一般运行信息,系统启动,任务完成,资源加载等(用户可以看到) |
warn | 非致命问题,程序还可以运行,如配置异常,网络抖动(可忽略但需注意) |
error | 程序运行失败,如读取文件失败,通信断开(需重点关注) |
critical | 致命错误,系统可能崩溃或者立即介入,如系统异常终止(报警级别) |
创建logger
获取实例是线程安全的
1.工厂方法创建
auto logger = spdlog::srdout_color_mt("console");
2.手动创建
auto sink = make_shared<spdlog::sinks::stdout_color_sink_mt>();
auto logger = make_shared<spdlog::logger>("logger",sink);
spdlog::register_logger(logger);
3.注册logger,目的为了全局访问
spdlog::get("logger")->info("Hello from anywhere!");
创建sink
已有的sink
stdout_color_sink_mt //彩色终端输出basic_file_sink_mt //写入基础文件rotating_file_sink_mt //日志轮转(按照文件大小)daily_file_sink_mt //每天生成一个日志文件null_sink_mt //静默输出
自定义sink
继承 spdlog::sink::base_sink 或 sink 实现 sink_it_() 和 flush_() 方法即可
自定义格式化
1.set_pattern
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
2.flags
- %v:日志内容
- %t : 线程ID
- %s:源文件名
- %#:源代码行号
- %!:函数名
- %^ %$:高亮开头/结尾
3.源文件定位flags
SPDLOG_LOGGER_CALL(logger,spdlog::level::info,"msg");
创建异步日志
1.使用async_factory
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"auto logger = spdlog::basic_logger_mt<spdlog::async_factory>("async_logger", "async.txt");
2.creat_async
auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("async.txt",true);
logger = spdlog::create_async("async_logger",sink);
3.create_async_nb,非阻塞写法,不阻塞主线程写入日志
auto logger = spdlog::create_async_nb<spdlog::sink::basic_file_sink_mt>("async_nb_looger","nb.txt");
4.async_logger
spdlog::init_thread_pool(8192,1);auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("custom.txt",true);
auto async_logger = std::make_shared<spdlog::async_logger>("custom_async",sink,spdlog::thread_pool(),spdlog::async_overflow_policy::block);spdlog::register_logger(async_logger);
刷新策略
1.手动flush
logger->flush();
2.条件flush
spdlog::flush_on(spdlog::level::err);
3.间隔flush
spdlog::flush_every(std::chrono::seconds(3));
实例演示
控制台打印
#include <spdlog/spdlog.h>#include <string.h>#include <iostream>int main(){// 普通打印spdlog::info("Welcome to info spdlog!");// 格式化打印// 打印字符串spdlog::info("Hello World {}", "spdlog!");// 打印数字spdlog::error("spdlog errCode : {}", -10020);// 指定打印数字的占位符spdlog::warn("spdlog format char {:08d}", 12);// 格式化打印不同进制的数据spdlog::critical("Support for int:{0:d} hex:{0:x} oct:{0:o} bin:{0:b}", 42);// 打印浮点型数据spdlog::info("float args are {:03.2f}", 1.23456);// 打印多个参数spdlog::info("string args are {0} {1}..", "too", "supported");spdlog::info("number args are {0} {1} {2}..", 10020, 10040, -100);system("pause");}
参数是以{},传入的。
资源分享:0voice · GitHub