文章目录
- 1. 简介
- 1.1. spdlog代码特点
- 1.2. 说明
- 1.3. spdlog架构
- 2. spdlog的安装
- 2.1. 使用包管理器安装
- 2.2. 使用源码安装
- 2.3. 仅使用头文件
- 3. 相关概念
- 3.0 常用的头文件
- 3.1. level_enum
- 3.2. sink
- 3.3. logger
- 3.4 格式输出
- 3.5 对齐方式
- 3.6 截断
- 3.7 字符串格式化fmt
- 4. 特性
- 4.1. 特性——同步、异步
- 4.2. 特性——单、多线程处理模式
- 4.3. 特性——个性化输出格式(pattern)
- 4.4. 特性——刷新机制
- 4.5. 特性——异常处理
- 4.6. 特性——日志类型
- 5. 日志输出
- 5.1. 基本文件
- 5.2. 循环文件
- 5.3. 每日文件
- 参考链接
1. 简介
spdlog是开源、高性能、快速、跨平台,支持header-only/compiled的C++日志库,spdlog是基于C++11实现的一款纯头文件的日志管理库。
Git地址
API说明
应用示例
WiKi
1.1. spdlog代码特点
spdlog主要基于C++11开发(若编译环境支持C++20,则将使用std::fmt取代第三方fmt库)。
spdlog中大量使用移动语义、完美转发以减少对象拷贝,又利用内联、模板等技术尽量减少了抽象的代价。
同时广泛使用了智能指针等降低了内存管理的复杂性,通过spdlog可以深入的了解C++11的优雅实现。
1.2. 说明
高效与快速:
Spdlog 专注于提供极致的性能,在大量日志记录场景下也能保持较低的延迟和较高的吞吐量。轻量化设计:
Spdlog 是头文件(header-only)库,这意味着用户只需要包含相应的头文件即可开始使用,无需编译链接额外的库文件,即:将spdlog/include目录下的文件拷贝到你的项目中,仅包含头文件即可。跨平台支持:
它支持多种操作系统,包括但不限于 Windows、Linux 和 macOS(Linux / Windows on 32/64 bits),并且在这些平台上都能够良好运行。丰富的日志级别:
Spdlog 支持常见的日志级别,如 TRACE、DEBUG、INFO、WARN、ERROR、CRITICAL 等,用户可以根据需要选择不同级别的日志输出。格式化与定位信息,可自定义日志格式:
通过集成 fmt(fmtlib) 库,Spdlog 允许用户自定义日志消息的格式,可以轻松地包含时间戳、线程ID、文件名、行号以及函数名等上下文信息。多目标输出:
可以将日志输出到控制台、普通文本文件、循环写入文件(rotating log files)、每日生成新文件(daily logs)、系统日志等目标,同时也支持异步写入以提高性能。线程安全:
对于多线程环境,Spdlog 提供了线程安全的日志接口,确保在并发环境下日志记录的正确性和完整性。
spdlog中各对象都分为多线程与单线程版本:_st
:单线程版本,不用加锁,效率更高。*_mt
:多线程版本,用于多线程程序是线程安全的。
异步模式:
提供可选的异步日志记录机制,能够将日志操作放入后台线程执行,从而避免阻塞主线程。条件日志:
根据预定义的条件开关,可以动态启用或禁用特定级别的日志输出,例如: 可自定义文档大小;可实现自动按日期创建日志文件/定时创建日志文件。
1.3. spdlog架构
spdlog可以分成三级结构,从上而下是logger registry、logger、sink。
-
logger/async_logger(日志记录器)
日志处理的入口,负责格式化日志信息、日志信息的整理合并(如日志级别、文件名、函数名、文件行号等),最终封装至log_msg对象中,再将log_msg对象投递给下游处理。是用户直接操作的对象,通过操作logger进行日志逻辑的生成。logger与aync_logger区别在于:
1)logger是同步处理,会由调用日志记录的线程直接将封装后的log_msg对象投递给下游的sink。
2)aync_logger则是异步处理,调用日志记录的线程仅负责将封装后的log_msg对象放入线程安全队列,后续由线程池从线程安全队列中不断处理队列中的日志对象。
一个logger对象中存储有多个sink,当调用logger的日志输出函数时,logger会调用自身存储的所有sink对象的log(log_msg) 函数进行输出。logger中主要包括:
set_pattern(const std::string&):设置logger包含的所有sink的日志输出内容格式。
set_level(level_enum):设置logger日志输出最低等级,如果logger包含的sink没有设置日志等级的话,则会为其设置日志等级。
log(level_enum level,log_msg content):按照level等级进行输出content,logger其中日志输出最低等级小于或等于level的sink会进行执行输出操作。
trace(content,arg1,arg2…):按照trace等级进行输出,输出内容由content与后面的参数格式化而成。同类的函数还包括:debug/info/warn…。
- sink(日志记录槽)
受logger控制,执行具体的动作(动作包括写入日志文件/输出到控制台),即:负责接收log_msg对象,并通过formatter将对象中记录的信息转换为字符串,最终将字符串输出到目标位置(控制台、日志文件等)。
spdlog定义了几种sinks用于不同场景(也可自定义)下的日志输出,sink中主要包含:
set_pattern(const std::string&):设置日志输出的内容格式。
set_level(level_enum): 设置日志输出的最低等级。
log(log_msg):由logger自动调用,外部不会主动调用。
-
formatter
负责将log_msg对象中的信息转换成字符串。
通过set_pattern可设定日志格式,如set_pattern("[%Y-%m-%d %H:%M:%S.%e][%l](%@): %v")
; -
registry(logger registry 日志管理器)
负责管理所有的logger(创建、销毁、获取等),并且通过registry还可对所有的logger做全局设置。例如可通过spdlog::get()
访问已创建的logger。 -
总结
简单来说,就是一个logger registry管多个logger,一个logger管多个sink。
logger registry中的logger是通过name进行对应的。后面使用的时候可以直接通过名称获取对应的日志对象。
有了这种层级结构,在代码调用的时候,logger的每个操作都会下顺到sink层面,调用sink的对象。比如像一些set_pattern()
和set_level()
。说到底,日志库的目的就是把日志信息写到指定地方。从上面对于结构的功能描述,sink才是真正操作日志进行写操作的结构。
那sink可以把日志信息写到哪里呢?主要有三个去向:1) 控制台输出(stdout)——默认输出方式 2) 日志文件 3) 数据库或其他外部实体
从使用的角度上讲,用文件存储日志比直接存储在数据库中更加常用一点。
2. spdlog的安装
2.1. 使用包管理器安装
- Debian:
sudo apt install libspdlog-dev
- Homebrew:
brew install spdlog
- MacPorts:
sudo port install spdlog
- FreeBSD:
pkg install spdlog
- Fedora:
dnf install spdlog
- Gentoo:
emerge dev-libs/spdlog
- Arch Linux:
pacman -S spdlog
- openSUSE:
sudo zypper in spdlog-devel
- vcpkg:
vcpkg install spdlog
- conan:
spdlog/[>=1.4.1]
- conda:
conda install -c conda-forge spdlog
- build2:
depends: spdlog ^1.8.2
2.2. 使用源码安装
$ git clone https://github.com/gabime/spdlog.git
$ cd spdlog && mkdir build && cd build
$ cmake .. && make -j
2.3. 仅使用头文件
将spdlog/include目录下的文件拷贝到你的项目中即可。
3. 相关概念
3.0 常用的头文件
#include "include/spdlog/spdlog.h"
#include "include/spdlog/sinks/stdout_color_sinks.h"
//根据放置库的位置,编写对应的头文件: #include "spdlog/sinks/basic_file_sink.h"
#include "include/spdlog/sinks/basic_file_sink.h"
#include "include/spdlog/sinks/rotating_file_sink.h"
#include "include/spdlog/sinks/daily_file_sink.h"
#include "include/spdlog/sinks/dist_sink.h"
#include <afxcontrolbars.h>
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE //需要输出文件名和行号,必须输出这个宏
using namespace spdlog;
#include <memory>
#include <string>
#include <conio.h>
#include "spdlog/spdlog.h"
#include "spdlog/fmt/bin_to_hex.h"
#include "spdlog/fmt/bundled/core.h"
#include "spdlog/fmt/bundled/args.h"
#include "spdlog/fmt/bundled/format.h"
// 设置为智能指针类型,用于在 C++ 中管理 spdlog::logger 类型对象的生命周期
extern std::shared_ptr<spdlog::logger> myLogger;
std::shared_ptr<spdlog::logger> myLogger;
3.1. level_enum
日志级别,定义如下:
enum class level_enum {
trace = SPDLOG_LEVEL_TRACE 0
debug = SPDLOG_LEVEL_DEBUG 1
info = SPDLOG_LEVEL_INFO 2(默认输出等级)
warn = SPDLOG_LEVEL_WARN 3
err = SPDLOG_LEVEL_ERROR 4
critical = SPDLOG_LEVEL_CRITICAL 5
off = SPDLOG_LEVEL_OFF 6
}
设置某个等级后,小于该等级的日志将不会被记录。
3.2. sink
日志记录器槽,用于设置日志的输出目的地,如控制台、文件等。
常用函数:
1. virtual void log(const details::log_msg &msg) = 0; //记录日志,有logger自动调用
2. virtual void flush() = 0; // 刷新日志
//用于设置日志消息的格式模板。通过指定格式模板,你可以控制日志消息的外观,包括日期、时间、日志级别、线程ID、日志内容等等。
//例如:(`set_pattern("[%Y-%m-%d %H:%M:%S.%e][%l](%@): %v")`)
3. virtual void set_pattern(const std::string &pattern) = 0;
// 设置自定义的格式化器
4. virtual void set_formatter(std::unique_ptr<spdlog::formatter>sink_formatter) = 0;
5. void set_level(level::level_enum log_level); //设置输出日志的最低级别
6. level::level_enum level() const; // 获取日志级别
7. bool should_log(level::level_enum msg_level) const; //判断是否需要记录日志
set_formatter
方法用于设置自定义的日志消息格式化器。通过设置自定义格式化器,你可以完全掌控日志消息的外观,而不仅仅是使用预定义的格式模板。
3.3. logger
日志记录器,用于记录日志。
一个logger对象中存储有多个sink,当调用logger的日志输出函数时,logger会调用自身存储的所有sink对象的log(log_msg) 函数进行输出。与自带的sink对应,spdlog也自带了几种logger。
logger类主要使用的函数包括:
template<typename T>
void trace(const T &msg) // 记录trace级别的日志
{
log(level::trace, msg);
}
template<typename T>
void debug(const T &msg) // 记录debug级别的日志
{
log(level::debug, msg);
}
template<typename T>
void info(const T &msg)
{
log(level::info, msg);
}
template<typename T>
void warn(const T &msg)
{
log(level::warn, msg);
}
template<typename T>
void error(const T &msg)
{
log(level::err, msg);
}
template<typename T>
void critical(const T &msg)
{
log(level::critical, msg);
}
// return true logging is enabled for the given level.
bool should_log(level::level_enum msg_level) const
{
return msg_level >= level_.load(std::memory_order_relaxed);
}
// return true if backtrace logging is enabled.
bool should_backtrace() const
{
return tracer_.enabled();
}
void set_level(level::level_enum log_level); // 设置日志级别
level::level_enum level() const;
const std::string &name() const;
// set formatting for the sinks in this logger.
// each sink will get a separate instance of the formatter object.
void set_formatter(std::unique_ptr<formatter> f);
// set formatting for the sinks in this logger.
// equivalent to
// set_formatter(make_unique<pattern_formatter>(pattern, time_type))
// Note: each sink will get a new instance of a formatter object, replacing the old one.
void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local);
// backtrace support.
// efficiently store all debug/trace messages in a circular buffer until needed for debugging.
void enable_backtrace(size_t n_messages);
void disable_backtrace();
void dump_backtrace();
// flush functions
void flush();
void flush_on(level::level_enum log_level);
level::level_enum flush_level() const;
// sinks
const std::vector<sink_ptr> &sinks() const;
std::vector<sink_ptr> &sinks();
// error handler
void set_error_handler(err_handler);
// create new logger with same sinks and configuration.
virtual std::shared_ptr<logger> clone(std::string logger_name);
3.4 格式输出
通过set_pattern可设定日志格式,如set_pattern("[%Y-%m-%d %H:%M:%S.%e][%l](%@): %v")
;
flag | meaning | example |
---|---|---|
%v | 日志内容 | “my log test content” |
%t | 线程ID | “123” |
%P | 进程ID | “234” |
%n | 记录器Logger名 | “basicLogger” |
%l | 日志级别 | “debug”, “info”, etc |
%L | 日志级别简称 | “D”, “I”, etc |
%a | 星期几(简称) | “Thu” |
%A | 星期几 | “Thursday” |
%b | 月份简称 | “Aug” |
%B | 月份 | “August” |
%c | 日期时间 | “Thu Aug 23 15:35:46 2014” |
%C | 年(两位) | “14” |
%Y | 年 | “2014” |
%D %x | 日期简写 | “08/23/14” |
%m | 月份(数字) | “11” |
%d | 日(数组) | “29” |
%H | 小时(24制) | “23” |
%I | 小时(12制) | “11” |
%M | 分钟 | “59” |
%S | 秒 | “58” |
%e | 毫秒 | “678” |
%f | 微秒 | “056789” |
%F | 纳秒 | “256789123” |
%p | AM/PM | “AM” |
%r | 时间(12制) | “02:55:02 pm” |
%R | 时分(24制) | “23:55” |
%T %X | 时间(24制) | “23:55:59” |
%z | 时区(偏移) | “+02:00” |
%E | epoch(秒) | “1528834770” |
%% | 百分号 | “%” |
%+ | 默认格式 | “[2014-10-31 23:46:59.678] [mylogger] [info] Some message” |
%^ | start color range (can be used only once) | “[mylogger] [info(green)] Some message” |
%$ | end color range (for example %^ [+++]%$ %v) (can be used only once) | [+++] Some message |
%@ | 文件名与行数 | my_file.cpp:123 |
%s | 文件名 | my_file.cpp |
%g | 文件名(含路径) | /some/dir/my_file.cpp |
%# | 行数 | 123 |
%! | 函数名 | my_func |
%o | 相对上一条记录的时间间隔(毫秒) | 456 |
%i | 相对上一条记录的时间间隔(微秒) | 456 |
%u | 相对上一条记录的时间间隔(纳秒) | 11456 |
%O | 相对上一条记录的时间间隔(秒) | 4 |
日志输出中要携带文件名、行数或函数名时,必须使用SPDLOG_LOGGER_*宏
,且要激活对应的级别(哪些级别以上的日志会被记录):
// 记录INFO及以上级别日志
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
#include "spdlog/spdlog.h"
SPDLOG_LOGGER_INFO(myLogger, "Support for floats {:03.2f}", 1.23456);
SPDLOG_LOGGER_WARN(myLogger, "Easy padding in numbers like {:08d}", 12);
3.5 对齐方式
每个flag都可携带对齐方式(最多支持64字符),
align | meaning | example | result |
---|---|---|---|
% | 右对齐 | %8l | " info" |
%- | 左对齐 | %-8l | "info " |
%= | 居中 | %=8l | " info " |
3.6 截断
截断: 通过可设定对应输出的最大长度:
align | meaning | example | result |
---|---|---|---|
%! | 右对齐且截断 | %3!l | “inf” |
%-! | 左对齐且截断 | %-2!l | “in” |
%=! | 居中且截断 | %=1!l | “i” |
3.7 字符串格式化fmt
spdlog中字符串格式化使用fmt库。
格式化方式:{ [arg_id] [: (format_spec | chrono_format_spec)] }
- arg_id:参数标识;
- 忽略(为空时),依次对应每一个参数;
- 索引(数字,从0开始),引用第几个索引;
- 名称,命名参数;
- format_spec:参数格式化方式(类型、对齐、填充等);
Format Specification
格式化符说明:
format_spec ::= [[fill]align][sign]["#"]["0"][width]["." precision]["L"][type]
fill ::= <a character other than '{' or '}'>
align ::= "<" | ">" | "^" // 左、右、居中对齐
sign ::= "+" | "-" | " "
width ::= integer | {[arg_id]} // 宽度:数字或指定的参数
precision ::= integer | {[arg_id]} // 精度:数字或指定的参数
type ::= "a" | "A" | "b" | "B" | "c" | "d" | "e" | "E" | "f" | "F"
| "g" | "G" | "o" | "p" | "s" | "x" | "X"
不同的转换下有不同的意义:
- 整数时,表示前面添加进制前缀,如0x, 0b等;
- 浮点数时:总是有小数点(即使没有小数部分);
L只对数字有效,根据本地设置来输出:如,
auto s = fmt::format(std::locale("en_US.UTF-8"), "{:L}", 1234567890);
// s == "1,234,567,890"
格式化类型:
type | meaning |
---|---|
s | 字符串 |
c | 字符 |
b/B | 二进制 |
d | 数字(十进制) |
o | 八进制 |
x/X | 十六进制 |
a/A | 十六进制浮点数(p表示指数) |
e/E | 科学计数 |
f/F | 浮点数(包括NAN,INF),固定小数位数输出 |
g/G | 浮点数输出 |
p | 指针 |
示例:
fmt::format("{:*^30}", "centered"); // use '*' as a fill char
// Result: "***********centered***********"
fmt::format("{:#04x}", 0);
// Result: "0x00"
fmt::print(
"┌{0:─^{2}}┐\n"
"│{1: ^{2}}│\n"
"└{0:─^{2}}┘\n", "", "Hello, world!", 20);
┌────────────────────┐
│ Hello, world! │
└────────────────────┘
4. 特性
4.1. 特性——同步、异步
这里的同步/异步指日志信息是否直接输出/写入文件,直接写就是同步,稍后写就是异步。spdlog默认的状态就是同步了,同步也没什么好说的。
这里介绍下异步的逻辑实现:
异步状态下,日志会先存入队列,然后由线程从队列中取数据,当队列满的时候会有淘汰策略。如果工作线程中抛出了异常,向队列写入下一条日志时异常会再次抛出,可以在写入队列时捕捉工作者线程的异常,淘汰策略一般两种:
- 阻塞新来的的日志,直到队列有剩余空间(默认处理方式)
- 把新的日志丢掉(需要设定:spdlog::set_async_mode(队列大小,spdlog::async_overflow_policy::discard_log_msg))
4.2. 特性——单、多线程处理模式
spdlog中提供了单线程和多线程模式,由使用者在对象创建中自己指定。
- st:单线程版本,不用加锁,效率高,但不保证线程安全
- mt:多线程版本,保证多线程并发情况线程安全,但效率稍低
4.3. 特性——个性化输出格式(pattern)
一般情况下,希望输出的日志信息中带有各类基本信息。
但具体情况要具体分析,spdlog中提供了个性化的输出方式,可以自己指定模式进行输出。
基本上就是各类“%参数”的组合。具体内容可以参考:Custom formatting 。
4.4. 特性——刷新机制
spdlog使用中需要设置刷新规则,以防止诸如程序闪退时日志未及时写入导致无法通过日志内容分析程序崩溃原因。
spdlog刷新设置主要有两种设置方式,一种是全局设置,一种是对于重要的日志信息之后,立即写入。
两种刷新方式:
- 程序正常退出时写入(默认)
- 程序运行中,在指定位置进行写入(实时刷新日志,便于锁定错误所在位置)
全局设置支持设置刷新周期和刷新级别两种方式。flush_on()
和flush_every()
。
要想使用实时刷新日志,spdlog提供了两种方法:
方法一:logger对象->flush_on(设定等级),flush_on是一次性刷新,执行到此时按照设定等级进行日志刷新。
方法二:logger对象->flush_every(周期时间),flush_every是设置刷新周期,定时进行刷新。刷新的级别采取默认了。
示例:
//定时刷新日志缓冲区
spdlog::flush_every(std::chrono::seconds(3));
// trigger flush if the log severity is error or higher 如果日志严重性为错误或更高,则触发刷新
daily_logger->flush_on(spdlog::level::err);
// 刷新缓冲区
my_logger->flush();
4.5. 特性——异常处理
对于日志库来说,当异常发生时,应该要输出异常出现的位置。spdlog会向std::err打印一条语句(终端可显示)。为了防止异常语句刷屏,打印的频率固定在每分钟一条。
实例:
try
{
//设置循环输出的日志
my_logger= spdlog::rotating_logger_mt("hil", "log.txt", 1024 * 1024 * 5, 2);
my_logger->set_level(spdlog::level::debug);
//启动在调用hillo->trace的时候把日志放到一个ringbuffer(环形内存)里面,最多64条日志
my_logger->enable_backtrace(64);
//定时刷新
spdlog::flush_every(std::chrono::seconds(3));
}
catch (const spdlog::spdlog_ex& ex)
{
return 0;
}
#define FLUSHLOG() do{if(my_logger){my_logger->flush();}}while(0)
#define DUMP_LOGTRACE() do{if(my_logger){my_logger->dump_backtrace();}}while(0)
4.6. 特性——日志类型
根据输出类型基本可分为输出到终端和文件两种类型,其中输出文件类型可进一步分为按文件大小和日期滚动刷新。
- 按日期滚动刷新是指每隔24小时,到达指定的时间后会创建新的日志文件;
- 按文件大小滚动刷新是指日志文件尺寸达到设定值后,会将当前文件添加后缀进行重命名,然后创建新的空日志文件进行写入。
此外,spdlog还支持自定义日志写入规则,可通过自定义sink类实现。
日志格式设置
spdlog支持自定义日志格式,但是自定义的logger往往不支持自定义格式,需要使用spdlog提供的宏定义调用,可以实现自定义输出格式。
相关术语
术语 | 释义 |
---|---|
logger | 用于记录日志的对象 |
rotate | 日志文件的切换 |
registry | 注册处,从统一一个位置来获得logger |
sink | 实际执行落日志到文件或DB动作的类 |
mt | multiple-thread 的缩写,带_mt后缀的是多线程安全的 |
st | single-thread的缩写,带_st的函数非线程安全的 |
ex | exception的缩写,spdlog::spdlog_ex |
slot | 插槽,在spdlog线程池构造时,预分配queue slot |
tweaking | (稍稍改进),自己可以指定一些参数。 |
flush | 刷日志 |
bundled | 捆绑的,spdlog/include/spdlog/fmt/bundled/ 使用的外部库的代码 |
5. 日志输出
spdlog,作为一个高性能的C++日志库,提供了多种灵活的日志输出方式,以满足不同场景下的需求。以下是spdlog几种正常的输出方式的详细说明:
- 控制台输出(stdout)
说明:这是spdlog的默认输出方式之一,即将日志信息直接打印到控制台(通常是终端或命令行界面)。
特点:便于开发者即时查看日志信息,特别是在开发过程中进行调试时。
示例:通过包含spdlog/spdlog.h头文件并使用spdlog::info等函数直接输出日志到控制台。 - 文件输出
基本文件日志(spdlog::basic_logger):
说明:创建一个只向单个文件写入日志的日志器。
特点:所有日志都会在该文件中累加,适用于不需要频繁轮转日志文件的场景。
示例:使用spdlog::basic_logger_mt(多线程安全版本)创建一个日志器,并指定文件名。
循环日志(spdlog::rotating_logger):
说明:当日志文件达到一定大小时,会自动创建一个新的日志文件继续写入,而旧的日志文件会被保留(但数量有限制)。
特点:适用于日志文件可能会快速增长的场景,可以有效管理磁盘空间。
示例:使用spdlog::rotating_logger_mt函数,指定文件名、最大文件大小和最大文件数量。
按天轮转日志(spdlog::daily_logger):
说明:每天在指定的时间点创建一个新的日志文件,并开始向新文件写入日志。
特点:便于按天管理日志,便于后续分析和归档。
示例:使用spdlog::daily_logger_mt函数,指定文件名和每天的轮转时间(小时和分钟)。 - 系统日志输出
说明:虽然spdlog本身可能不直接提供将日志输出到系统日志(如syslog)的功能,但可以通过集成或封装其他库(如syslog-ng、rsyslog等)来实现。
特点:系统日志通常由操作系统管理,适合需要与系统其他部分集成或符合特定日志管理规范的场景。 - 自定义输出
说明:spdlog支持通过自定义sink(日志接收器)来实现自定义的日志输出方式。
特点:高度灵活,可以根据实际需求将日志输出到数据库、网络、自定义消息队列等。
示例:通过继承spdlog::sink类并实现相关接口,可以创建自定义的sink来接收日志信息。 - 异步输出
说明:spdlog提供了异步日志记录机制,可以将日志操作放入后台线程执行,避免阻塞主线程。
特点:提高程序性能,特别是在高并发或日志量大的场景下。
示例:使用spdlog::async_logger或相关函数创建异步日志器。
综上所述,spdlog提供了包括控制台输出、文件输出(基本文件日志、循环日志、按天轮转日志)、系统日志输出(通过集成)、自定义输出以及异步输出在内的多种日志输出方式。这些方式使得spdlog能够灵活适应不同场景下的日志记录需求。
5.1. 基本文件
最简单的日志文件:
#include "spdlog/sinks/basic_file_sink.h"
void basic_logfile_example()
{
try
{
auto logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
}
catch (const spdlog::spdlog_ex &ex)
{
std::cout << "Log init failed: " << ex.what() << std::endl;
}
}
5.2. 循环文件
日志文件超过指定大小后,自动生成一个新的;并且只保留最多指定数量的日志文件:
#include "spdlog/sinks/rotating_file_sink.h"
void rotating_example()
{
// Create a file rotating logger with 5mb size max and 3 rotated files
auto max_size = 1024*1024 * 5;
auto max_files = 3;
auto logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", max_size, max_files);
}
5.3. 每日文件
每天指定时间生成一个新的日志文件:
#include "spdlog/sinks/daily_file_sink.h"
void daily_example()
{
// Create a daily logger - a new file is created every day on 2:30am
auto logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
}
完整示例
设定默认日志记录文件并在不同地方获取使用:
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
#include "spdlog/spdlog.h"
#include "spdlog/sinks/rotating_file_sink.h"
void writeLog(int n) {
for (int i = 0; i < n; ++i) {
// 获取logger后输出日志
auto myLogger = spdlog::get("baseLogger");
myLogger->info("{}: Hello, {}!", i + 1, "World");
myLogger->info("Welcome to spdlog!");
myLogger->error("Some error message with arg: {}", 1);
// 带文件名与行号的日志输出
SPDLOG_LOGGER_INFO(myLogger, "Support for floats {:03.2f}", 1.23456);
SPDLOG_LOGGER_WARN(myLogger, "Easy padding in numbers like {:08d}", 12);
// 输出到默认日志中
spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
spdlog::error("Some error message with arg: {}", 1);
spdlog::warn("Easy padding in numbers like {:08d}", 12);
spdlog::info("Support for floats {:03.2f}", 1.23456);
}
}
void testSPDLog() {
// 设定日志最大100k,且最多保留10个
auto myLogger = spdlog::rotating_logger_mt("baseLogger", "logs/basic.log", 1024 * 100, 10);
spdlog::set_default_logger(myLogger);
myLogger->set_pattern("[%Y-%m-%d %H:%M:%S.%e][%l](%@): %v"); // 非通过宏输出的日志%@输出为空
myLogger->set_level(spdlog::level::info);
myLogger->info("Hello, {}!", "World");
writeLog(10);
}
参考链接
[C++]-日志记录库SPDLog简介
spdlog使用学习笔记
C++日志记录库SPDLog
C++日志记录库SPDLog_V
字符串资源_1
字符串资源_2
spdlog
spdlog 快速的 C++ 日志库
C++高性能日志库spdlog使用指南
C++日志记录库SPDLog简介
轻量级C++11日志库spdlog
spdlog使用_蜗牛单行道的博客-CSDN博客_spdlog
spdlog学习笔记_haojie_superstar的博客-CSDN博客_spdlog
[C++]-日志记录库SPDLog简介[通俗易懂] - 全栈程序员必看 (javaforall.cn)
spdlog简介_JontyZh的博客-CSDN博客_spdlog 输出格式
spdlog 基本结构分析 - 小胖西瓜 - 博客园 (cnblogs.com)