目录
1.前言
每个记录器的接收器sink都有一个格式化器,用于将消息格式化到其目的地。
spdlog的默认日志记录格式为:
[2014-10-31 23:46:59.678] [my_loggername] [info] Some message
有两种方法可以自定义记录器的格式:
1)设置模式字符串(推荐):
set_pattern(pattern_string);
2) 实现实现格式化程序接口和调用的自定义格式化程序:
set_formatter(std::make_unique<my_custom_formater>());
2.使用set_pattern(..)自定义格式符号
格式可以全局应用于所有注册的记录器 loggers:
spdlog::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
或者用于特定的记录器 loggers:
some_logger->set_pattern(">>>>>>>>> %H:%M:%S %z %v <<<<<<<<<");
或者用于特定sink对象:
some_logger->sinks()[0]->set_pattern(">>>>>>>>> %H:%M:%S %z %v <<<<<<<<<");
some_logger->sinks()[1]->set_pattern("..");
3.格式化标记符(Pattern flags)
格式化标记符以%flag的形式出现,类似于strftime函数。以下是一些常用的模式标志及其含义:
标记 | 含义 | 例子 |
---|---|---|
%v | 要记录的实际文本 |
"some user text" |
%t | 线程ID |
"1232" |
%P | 进程ID |
"3456" |
%n | logger的名称 |
"some logger name" |
%l | 消息的日志级别(如"debug"、"info"等) |
"debug", "info", etc |
%L | 消息的简短日志级别(如"D"、"I"等) |
"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 | 短日期格式(MM/DD/YY) |
"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 | 时间表示法 | "02:55:02 PM" |
%R | 时间表示法 | "23:55" |
%T 或 %X | 时间表示法 | "23:55:59" |
%z | ISO 8601与UTC的时区偏移量([+/-]HH:MM) | "+02:00" |
%E | 自纪元以来的秒数 | "1528834770" |
%% | %符号 | "%" |
%+ | spdlog默认的格式 | "[2014-10-31 23:46:59.678] [mylogger] [info] Some message" |
%^ | 开始颜色范围 |
"[mylogger] [info(green)] Some message" |
%$ | 结束颜色范围 |
[+++] Some message |
%@ | 源文件和行号 | /some/dir/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 |
注意:如果你需要使用源代码定位相关的符号 %s
, %g
, %#
, %!,那你必须定义下面的宏:
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
(根据需要更改日志级别)并使用以下宏:
SPDLOG_LOGGER_TRACE(some_logger, "trace message");
SPDLOG_LOGGER_DEBUG(some_logger, "debug message");
SPDLOG_LOGGER_INFO(some_logger, "info message");
SPDLOG_LOGGER_WARN(some_logger, "warn message");
SPDLOG_LOGGER_ERROR(some_logger, "error message");
SPDLOG_LOGGER_CRITICAL(some_logger, "critical message");
打开SPDLOG_LOGGER_INFO、SPDLOG_LOGGER_CALL的宏定义:
# define SPDLOG_LOGGER_INFO(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::info, __VA_ARGS__)
# define SPDLOG_INFO(...) SPDLOG_LOGGER_INFO(spdlog::default_logger_raw(), __VA_ARGS__)
#define SPDLOG_LOGGER_CALL(logger, level, ...) (logger)->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__)
明白了把,SPDLOG_LOGGER_CALL宏把spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION} 传进去了,所以能打印源代码的位置和函数名了。
4.对齐方式
每个符号标志可以通过预先设置宽度数字(最多64)来对齐。
使用 "-"(左对齐)或 "="(居中对齐)控制对齐边:
对齐 | 含义 | 例子 | 结果 |
---|---|---|---|
%<width><flag> | 右对齐 | %8l | " info" |
%-<width><flag> | 左对齐 | %-8l | "info " |
%=<width><flag> | 中间对齐 | %=8l | " info " |
可选添加!如果结果的大小超过指定的宽度,则截断该结果:
对齐 | 含义 | 例子 | 结果 |
---|---|---|---|
%<width>!<flag> | 右对齐或截断 | %3!l | "inf" |
%-<width>!<flag> | 左对齐或截断 | %-2!l | "in" |
%=<width>!<flag> | 中间对齐或截断 | %=1!l | "i" |
5.扩展spdlog自定义格式
在spdlog中,扩展自定义标志允许您根据自己的需求定义新的日志格式标志。这通过继承custom_flag_formatter类并实现其clone()和format(...)抽象方法来完成。以下是如何在spdlog中扩展自定义标志的详细步骤:
步骤 1: 继承 custom_flag_formatter 类
首先,您需要创建一个继承自spdlog::custom_flag_formatter的类。在这个类中,您将定义您的新标志的逻辑。
步骤 2: 实现 clone() 方法
clone()方法需要返回一个当前对象的深拷贝。这是因为在spdlog中,每个接收器(sink)都会获得格式化器的一个新副本,以确保线程安全和避免潜在的竞态条件。
步骤 3: 实现 format(...) 方法
format(...)方法定义了当遇到您的自定义标记时,应该如何格式化日志消息。这个方法接收日志消息、时间戳和一个缓冲区,您需要将格式化后的文本追加到这个缓冲区中。
以下是一个示例,展示了如何添加一个名为%*的新自定义标志,该标志将向日志消息中添加自定义文本。
#include "spdlog/pattern_formatter.h"
class my_formatter_flag : public spdlog::custom_flag_formatter
{
public:
void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override
{
std::string some_txt = "custom-flag";
dest.append(some_txt.data(), some_txt.data() + some_txt.size());
}
std::unique_ptr<custom_flag_formatter> clone() const override
{
return spdlog::details::make_unique<my_formatter_flag>();
}
};
void custom_flags_example()
{
auto formatter = std::make_unique<spdlog::pattern_formatter>();
formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
spdlog::set_formatter(std::move(formatter));
}
请注意,上述示例中的(...)方法只是简单地添加了一段静态文本到日志消息中。根据您的具体需求,您可以在这个方法中添加更复杂的逻辑来格式化日志消息。