spdlog日志库--基础介绍
文章目录
- 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 0debug = SPDLOG_LEVEL_DEBUG 1info = SPDLOG_LEVEL_INFO 2(默认输出等级)warn = SPDLOG_LEVEL_WARN 3err = SPDLOG_LEVEL_ERROR 4critical = SPDLOG_LEVEL_CRITICAL 5off = 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 filesauto 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:30amauto 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)
相关文章:

spdlog日志库--基础介绍
文章目录 1. 简介1.1. spdlog代码特点1.2. 说明1.3. spdlog架构 2. spdlog的安装2.1. 使用包管理器安装2.2. 使用源码安装2.3. 仅使用头文件 3. 相关概念3.0 常用的头文件3.1. level_enum3.2. sink3.3. logger3.4 格式输出3.5 对齐方式3.6 截断3.7 字符串格式化fmt 4. 特性4.1.…...

【网络】网络编程套接字(二)
网络编程套接字(二) 文章目录 1.单执行流的TCP网络程序1.1服务端创建套接字1.2服务端绑定1.3服务端监听1.4服务端获取链接1.5服务端处理请求1.6客户端创建套接字1.7客户端连接服务器1.8客户端发起请求 2.多进程版的TCP网络程序2.1单执行流的弊端2.2多进…...

1.1、centos stream 9安装Kubernetes v1.30集群 环境说明
最近正在学习kubernetes,买了一套《Kubernetes权威指南 从Docker到Kubernetes实践全接触(第六版)》这本书讲得很好,上下两册,书中k8s的版本是V1.29,目前官网最新版本是v1.30。强烈建议大家买一套看看。 Kubernetes官网地址&#x…...
Redis3
目录 什么是缓存穿透?怎么解决? 什么是缓存雪崩?怎么解决? 如何保证数据库和缓存的数据一致性? 如何保证Redis服务高可用? 哨兵的作用 Redis虚拟槽分区有什么优点? 为什么Redis集群最大槽…...
Oracle数据巡检 - 设计巡检模板
设计巡检模板 明确巡检数据库等信息 包括数据库种类、版本、架构、数量等,例如 Oracle DG和Oracle RAC数据库巡检项肯定会有差异,Oracle 11g和12c版本巡检内容也会有所不同。 明确巡检项 这一块需要结合自身的运维经验,列出详尽的巡检项&…...

优盘未格式化数据恢复实战指南
在数字时代,优盘(USB闪存驱动器)作为便携存储媒介,承载着无数重要的文件与数据。然而,当您插入优盘准备访问资料时,却遭遇了“驱动器未被格式化”的提示,这无疑是一场突如其来的数据危机。本文将…...
【python基础】python基础习题练习(一)
文章目录 一. python语言简介二. python基本语法与常用函数三. python基本数据类型一.选择题二.编程题四. python组合数据类型一.选择题二.简答题三.编程题一. python语言简介 查看python是否安装成功的命令是:python -vPython IDE有:pyCharm、Spyder、Jupter NotebookPython…...
GESP 4级样题 ---> 绝对素数
这题需要判断一个数和它的反转后的数是否都为素数。 可以转成 string 后 reverse 一下。 AC CODE: #include <bits/stdc.h> using namespace std; typedef long long LL; bool isPrime(int x){if(x<2) return false;for(int i2;i*i<x;i){if(x%i0) re…...
大语言模型系列 - Transformer
1. 简介 1.1. 概述 大语言模型Transformer是一种由谷歌公司提出的基于注意力机制的神经网络模型,它在自然语言处理(NLP)领域取得了显著成就,并逐渐被应用于其他领域如语音识别、计算机视觉和强化学习等。 1.2. 学习资源 以下是一些学习大语言模型Transformer的资源地址…...

Java面试之操作系统
1、冯诺依曼模型 运算器、控制器、存储器、输入设备、输出设备 32位和64位CPU最主要区别是一次性能计算多少字节数据,如果计算的数额不超过 32 位数字的情况下,32 位和 64 位 CPU 之间没什么区别的,只有当计算超过 32 位数字的情况下&#…...

springboot船舶维保管理系统--论文源码调试讲解
第二章 相关技术 本次开发船舶维保管理系统使用的是Vue进行程序开发,船舶维保管理系统的数据信息选择MySQL数据库进行存放。 2.1 VUE介绍 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue…...

【机器学习西瓜书学习笔记——神经网络】
机器学习西瓜书学习笔记【第五章】 第五章 神经网络5.1神经元模型5.2 感知机与多层网络学习感知机学习率成本/损失函数梯度下降 5.3 BP神经网络(误差逆传播)5.4 全局最小与局部极小5.5 其他常见神经网络RBF网络RBF 与 BP 最重要的区别 ART网络 第五章 神…...

安装 electron 报错解决
1. 报错 大概率由镜像问题导致 2. 解决 2.1 打开 npm 配置 npm config edit 2.2 添加配置 registryhttps://registry.npmmirror.comelectron_mirrorhttps://cdn.npmmirror.com/binaries/electron/electron_builder_binaries_mirrorhttps://npmmirror.com/mirrors/electron…...

【Material-UI】Icon Button 组件详解
文章目录 一、基础用法1. 禁用状态 二、大小(Sizes)1. 小尺寸(Small)2. 大尺寸(Large) 三、颜色(Colors)1. 主题颜色2. 自定义颜色 四、高级用法和最佳实践1. 无障碍性(A…...

51单片机-第七节-DS1302实时时钟
一、DS1302介绍: 实时时钟芯片,可对年,月,日,周,时,分,秒计时,是一种集成电路。 二、DS1302原理: 1.寄存器定义: Command:操作模式…...

Java毕业设计 基于SSM和Vue的图书馆座位预约系统小程序
Java毕业设计 基于SSM和Vue的图书馆座位预约系统小程序 这篇博文将介绍一个基于SSM框架和Vue开发的图书馆座位预约系统微信小程序,适合用于Java毕业设计。 功能介绍 用户 登录 注册 首页 图片轮播 关于我们 公告信息 图书馆信息 图书馆详情 预约选座 收藏 …...

【C++11】:lambda表达式function包装器
目录 前言一,可变参数模板1.1 简单认识1.2 STL容器中的empalce系列相关接口 二,lambda表达式2.1 lambda表达式语法2.2 探索lambda底层 三,包装器3.1 function包装器3.2 bind 四,类的新功能4.1 默认成员函数4.2 关键字default4.3 关…...
[io]进程间通信 -有名、无名管道 区别
有名管道和无名管道的区别 无名管道有名管道 使用场景 亲缘关系进程不相关的任意进程特点 1.固定读端fd[0]写端fd[1] 2.文件IO进行操作 3.不支持lseek()操作 4.数据存储在内核空间 1.文件系统中存在管道文件 2.文件IO操作 3.不支持lseek 4.先进先出 5.数…...

pywinauto:Windows桌面应用自动化测试(七)
前言 上一篇文章地址: pywinauto:Windows桌面应用自动化测试(六)-CSDN博客 下一篇文章地址: 暂无 一、实战常用方法 1、通过Desktop快速获取窗口 通过之前章节我们了解到控制应用的方法为Application࿰…...
RGB++是什么;UTXO是什么;Nervos网络;CKB区块链;
目录 RGB++是什么,简单举例说明 RGB++简介 举例说明 UTXO是什么 定义 功能与特点 使用方式 优缺点 结论 CKB区块链 一、基础属性 二、技术特点 三、经济模型 四、应用场景 Nervos网络 一、网络架构 二、技术特点 三、经济模型 四、应用场景 五、未来展望 …...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...