文章目录
spdlog是一款开源的、快速的日志库。
spdlog库
spdlog是基于C++11实现的一款纯头文件的日志管理库(git地址:https://github.com/gabime/spdlog,API说明:https://spdlog.docsforge.com/v1.x/1.quickstart/):
- 配置特别简单,仅包含头文件即可;
- 写日志方式简单明了;
- 可实现自动按日期创建日志文件/定时创建日志文件;
- 可自定义日志格式;
- 可以输出当前输出日志所在的文件及函数;
- 可自定义文档大小;
- 可将不同级别的信息输出到不同日志文件;
- 多平台等。
spdlog中各对象都分为多线程与单线程版本:
*_st
:单线程版本,不用加锁,效率更高。*_mt
:多线程版本,用于多线程程序是线程安全的。
日志记录槽sink
spdlog定义了几种sinks用于不同场景(也可自定义)下的日志输出,sink中主要包含:
set_pattern(const std::string&)
:设置日志输出的内容格式。set_level(level_enum)
: 设置日志输出的最低等级。log(log_msg)
:由logger自动调用,外部不会主动调用。
日志记录器logger
一个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…。
输出格式pattern
通过set_pattern
可设定日志格式,如set_pattern("[%Y-%m-%d %H:%M:%S.%e][%l](%@): %v");
输出标记flag:
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);
对齐方式
每个flag都可携带对齐方式(最多支持64字符),
align |
meaning |
example |
result |
---|---|---|---|
%<width><flag> |
右对齐 |
%8l |
” info” |
%-<width><flag> |
左对齐 |
%-8l |
“info “ |
%=<width><flag> |
居中 |
%=8l |
” info “ |
截断
通过!可设定对应输出的最大长度:
align |
meaning |
example |
result |
---|---|---|---|
%<width>!<flag> |
右对齐且截断 |
%3!l |
“inf” |
%-<width>!<flag> |
左对齐且截断 |
%-2!l |
“in” |
%=<width>!<flag> |
居中且截断 |
%=1!l |
“i” |
字符串格式化fmt
spdlog中字符串格式化使用fmt(https://github.com/fmtlib/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! │
└────────────────────┘
spdlog使用
spdlog默认日志输出级别是INFO。
默认情况下,日志是同步模式的,可通过以下方法开启异步模式:
size_t q_size = 4096; //queue size must be power of 2
spdlog::set_async_mode(q_size);
在异步模式下,日志先存入队列(队列占用的内存 = 设置的队列大小 * slot的大小, 64位系统下slot大小为104字节。),再由工作者线程从队列中取出并输出。当队列满时,会根据设定策略处理:
异常处理
当输出日志时发生异常时,spdlog会向std::err 打印一条语句,为了避免输出的异常语句刷屏,打印频率被限制在每分钟一条。可通过set_error_handler来设定异常处理函数:
//can be set globaly or per logger(logger->set_error_handler(..))
spdlog::set_error_handler([](const std::string& msg)
{
std::cerr << "my err handler: " << msg << std::endl;
});
logger
默认情况下,spdlog的默认logger为输出到stdout:
# ifdef _WIN32
auto color_sink = std::make_shared<sinks::wincolor_stdout_sink_mt>();
# else
auto color_sink = std::make_shared<sinks::ansicolor_stdout_sink_mt>();
# endif
在使用完logger后,要关闭掉以释放(否则无再建立同名logger)
spdlog::drop_all(); // 关闭所有logger
spd::drop("basic_logger"); // 关闭指定logger
基础用法
spdlog中使用{}
(里面可指定格式)作为格式化符
以下方式把日志输出到默认logger上:
//#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
#include "spdlog/spdlog.h"
int main()
{
spdlog::info("{:<30}", "left aligned");
spdlog::warn("Easy padding in numbers like {:08d}", 12);
spdlog::error("Some error message with arg: {}", 1);
spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
spdlog::set_level(spdlog::level::debug); // Set global log level to debug
spdlog::debug("This message should be displayed..");
// change log pattern
spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");
// Compile time log levels
// define SPDLOG_ACTIVE_LEVEL to desired level
SPDLOG_TRACE("Some trace message with param {}", 42);
SPDLOG_DEBUG("Some debug message");
}
stdout日志
以彩色方式输出到标准输出设备上:
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
void stdout_example()
{
// create color multi threaded logger
auto console = spdlog::stdout_color_mt("console");
auto err_logger = spdlog::stderr_color_mt("stderr");
spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
}
文件日志
基本文件
最简单的日志文件:
#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;
}
}
循环文件
日志文件超过指定大小后,自动生成一个新的;并且只保留最多指定数量的日志文件:
#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);
}
每日文件
每天指定时间生成一个新的日志文件:
#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);
}
标签:输出,sink,set,C++,SPDLog,日志,logger,spdlog
From: https://www.cnblogs.com/lidabo/p/16902710.html