spdlog是一个高性能,超高速,零配置的C++日志库,它旨在提供简洁的API和丰富的功能,同时保持高性能的日志记录.它支持多种输出目标,个刷选项,线程安全以及异步日志记录.
spdlog的特点介绍:
- 高性能: spdlog专为速度而设计,即使在高负载情况下也能保持良好的性能.
- 零配置: 无需复杂的配置,只需要包含头文件即可在项目中使用.
- 异步日志: 支持异步日志记录,减少对主线程的影响.
- 格式化: 支持自定义日志的格式化,包括时间戳,线程id,日志级别等等.
- 多平台: 跨平台兼容,支持Windows,Linux,maxOS等操作系统.
- 丰富的API: 提供丰富的日志级别和操作符重载,方便记录各类类型的日志.
安装
fedora系统下安装:
shell
sudo dnf install -y spdlog-devel
源码安装
shell
$ git clone https://github.com/gabime/spdlog.git
$ cd spdlog && mkdir build && cd build
$ cmake .. && cmake --build .
标准日志输出
- 添加头文件
#include <spdlog/spdlog.h> - 创建日志对象
std::shared_ptr<logger> stdout_color_mt( const std::string &logger_name, color_mode mode = color_mode::automatic); - 设置日志输出等级
void set_level(level::level_enum log_level); - 设置日志输出格式
void set_pattern(std::string pattern, pattern_time_type time_type); - 输出日志
演示
C++
#include <iostream>
// 1. 添加头文件
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
int main(int argc,char* argv[])
{
// 2. 创建日志对象
auto logger = spdlog::stdout_color_mt("logger");
// 3. 设置日志输出等级
logger->set_level(spdlog::level::debug);
// 4. 设置日志输出格式
logger->set_pattern("[%H:%M:%S ][%-7l]:%v");
// 5. 输出日志
logger->debug("{}我是日志","test");
logger->info("{}我是日志","test");
logger->warn("{}我是日志","test");
logger->error("{}我是日志","test");
return 0;
}
打印:
txt
❯ ./sync
[17:10:46 ][debug ]:test我是日志
[17:10:46 ][info ]:test我是日志
[17:10:46 ][warning]:test我是日志
[17:10:46 ][error ]:test我是日志
输出到文件
c++
//指定⽂件
template<typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> basic_logger_mt(
const std::string &logger_name,
const filename_t &filename,
bool truncate = false,
const file_event_handlers &event_handlers = {}
演示
c++
#include <iostream>
// 1. 添加头文件
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
int main(int argc,char* argv[])
{
// 2. 创建日志对象
// auto logger = spdlog::stdout_color_mt("logger");
auto logger = spdlog::basic_logger_mt("logger","./log.log");
// 3. 设置日志输出等级
logger->set_level(spdlog::level::debug);
// 4. 设置日志输出格式
logger->set_pattern("[%H:%M:%S ][%-7l]:%v");
// 5. 输出日志
logger->debug("{}我是日志","test");
logger->info("{}我是日志","test");
logger->warn("{}我是日志","test");
logger->error("{}我是日志","test");
return 0;
循环文件输出
c++
//循环⽂件
template<typename Factory = spdlog::synchronous_factory>
std::shared_ptr<logger> rotating_logger_mt(
const std::string &logger_name,
const filename_t &filename,
size_t max_file_size,
size_t max_files,
bool rotate_on_open = false)
演示
c++
#include <iostream>
// 1. 添加头文件
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/rotating_file_sink.h>
int main(int argc,char* argv[])
{
// 2. 创建日志对象
// auto logger = spdlog::stdout_color_mt("logger");
// auto logger = spdlog::basic_logger_mt("logger","./log.log");
auto logger = spdlog::rotating_logger_mt("logger","./rotating.log",1024,3);
// 3. 设置日志输出等级
logger->set_level(spdlog::level::debug);
// 4. 设置日志输出格式
logger->set_pattern("[%H:%M:%S ][%-7l]:%v");
// 5. 输出日志
for(int i = 0;i<512;++i)
{
logger->error("test -- {}",i);
}
return 0;
}
异步输出
c++
using async_factory = async_factory_impl<async_overflow_policy::block>;
演示
c++
#include <iostream>
// 1. 添加头文件
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/async.h>
int main(int argc,char* argv[])
{
// 2. 创建日志对象
// auto logger = spdlog::stdout_color_mt("logger");
// auto logger = spdlog::basic_logger_mt("logger","./log.log");
auto logger = spdlog::rotating_logger_mt<spdlog::async_factory>("logger","./rotating_async.log",1024,3);
// 3. 设置日志输出等级
logger->set_level(spdlog::level::debug);
// 4. 设置日志输出格式
logger->set_pattern("[%H:%M:%S ][%-7l]:%v");
// 5. 输出日志
for(int i = 0;i<512;++i)
{
logger->error("test -- {}",i);
}
return 0;
}
介绍flush_on函数
spdlog为了提升性能,默认会把日志内容先存入内存缓冲区内,而不是立即写入文件/控制台等目标.
flush_on() 的作用就是:指定当日志级别达到某个阈值时,强制触发一次刷新操作,确保该级别及更高级别的日志能立刻落地,不会留在缓冲区里。
flush_on() 的具体作用
它的核心功能是设置 "自动刷新的日志级别阈值":
- 当调用
logger->flush_on(spdlog::level::warn);时,意味着:- 只要记录
warn、error、critical级别的日志,spdlog 就会立刻把缓冲区里的所有日志(包括之前的低级别日志,如 info/debug)刷新到目标;
- 只要记录
- 而低于该级别的日志(如 info/debug/trace),仍会按照默认策略缓冲(比如缓冲区满了、程序结束时才刷新)。
介绍daily_logger_format_mt函数
spdlog::daily_logger_mt 是 spdlog 中专门用于按日期自动分割日志文件的多线程安全日志器
daily_logger_mt(daily + logger + mt = 每日日志器 + 多线程安全)的核心功能是:
- 按日期 + 指定时间点自动创建新的日志文件,避免单个日志文件过大;
- 天生支持多线程(mt = multi-thread),可在多线程程序中安全使用;
- 继承了 spdlog 所有基础特性(如日志级别、刷新策略、格式化等)。
比如你设置每天凌晨 2 点分割日志,那么:
- 2026-01-23 02:00 前的日志会写入
app_2026-01-23.log; - 2026-01-24 02:00 会自动创建
app_2026-01-24.log,后续日志写入新文件。
二次封装
为什么要进行二次封装
- 避免单例的锁冲突,直接创建一个全局的线程安全的日志器进行使用.
- 使用宏进行二次封装输出日志的文件名和行号
- 封装出一个初始化接口,便于使用:调试模式则输出标准输出,否则输出到文件中.
思想:
封装出一个全局接口,用户进行日志器的创建与初始化,根据不同的运行模式选择不同的标准输出方式.
c++
#pragma once
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/sinks/daily_file_sink.h>
#include <spdlog/async.h>
// 定义全局的日志对象
std::shared_ptr<spdlog::logger> g_defult_logger;
/**
* @description 初始化日志系统
* @param
* mode:运行模式
* fileName:输出日志的路径
* level:发布模式下的日志输出等级
*/
void init_logger(bool mode, std::string &fileName, int32_t level)
{
// mode为真表示发布模式,mode为假表示调试模式
if (mode == false)
{
//打印到标准输出
g_defult_logger = spdlog::stdout_color_mt<spdlog::async_factory>("g_default_logger");
g_defult_logger->set_level(spdlog::level::level_enum::trace);
}
else
{
//打印到文件中
g_defult_logger = spdlog::daily_logger_format_mt<spdlog::async_factory>("g_default_logger", fileName, 0, 0);
g_defult_logger->set_level(static_cast<spdlog::level::level_enum>(level));
g_defult_logger->flush_on(spdlog::level::warn);
}
//日志输出格式
g_defult_logger->set_pattern("[%Y-%m-%d | %H:%M:%S] [%-7l]-> %v");
}
#define LOG_TRACE(format,...) g_defult_logger->trace("[{}:{}]: " format,__FILE__,__LINE__,##__VA_ARGS__);
#define LOG_DEBUG(format,...) g_defult_logger->debug("[{}:{}]: " format,__FILE__,__LINE__,##__VA_ARGS__);
#define LOG_INFO(format,...) g_defult_logger->info("[{}:{}]: " format,__FILE__,__LINE__,##__VA_ARGS__);
#define LOG_WARN(format,...) g_defult_logger->warn("[{}:{}]: " format,__FILE__,__LINE__,##__VA_ARGS__);
#define LOG_ERROR(format,...) g_defult_logger->error("[{}:{}]: " format,__FILE__,__LINE__,##__VA_ARGS__);
#define LOG_FATAL(format,...) g_defult_logger->critical("[{}:{}]: " format,__FILE__,__LINE__,##__VA_ARGS__);