Log:Spdlog初探
简介
公司需要开新项目,提议更换日志库,交给我让我调研一下spdlog库的使用。
spdlog简介
Github地址:Github地址
官网介绍:Very fast, header-only/compiled, C++ logging library。轻量,仅有头文件/编译,C++日志库。
注意:Spdlog包含了C++11特性,需使用支持C++11特性的编译器。
安装/使用
Header only version
只是用头文件版本。
官网说明:Copy the source folder to your build tree and use a C++11 compiler
.
复制源文件文件夹到的你编译链中 和 使用一个C++11编译器。
源文件地址:源文件地址
编译静态库
Linux版本
注意:本机需要安装好git,cmake。这里就不介绍安装git,还有cmake了。
$ git clone https://github.com/gabime/spdlog.git
$ cd spdlog && mkdir build && cd build
$ cmake .. && make -j
$ make install
- 1
- 2
- 3
- 4
命令翻译
1.克隆项目到当前目录,工程文件夹为 spdlog
2.进入 spdlog文件夹 && 创建build文件夹 && 进入build文件夹
3.执行cmkae .. 命令构建makefile工程 && make 编译
4.安装。此命令为安装到系统环境中,使用时就不需要配置引用头文件目录,库目录。\
如果不使用改命令,则需要在build 目录下的 lib文件夹找到编译好的库,在 include文件夹 在 引用的头
- 1
- 2
- 3
- 4
- 5
Windows版本
下载地址:spdlog工程下载地址
Windows下将下载好的 zip包或者 .tar.gz包解压到本地。构建cmake工程
注意:本机需要安装好cmake。cmake下载地址:cmake下载地址,下载版本:cmake-3.17.0-rc3-win64-x64.msi
解压spdlog.zip/spdlog.tar.gz 到 本地
进入spdlog-1.x目录,新建文件夹 build 文件夹,output 文件夹 //配置编译文件夹,编译输出文件夹
打开cmake-gui,配置cmake工程属性 (#后为按钮名称)
配置 CMakeLists.txt 路径,编译路径 #configure
配置 Visual Studio 编译器,平台版本。根据自己需要配置 #Finish
配置 其他属性,主要是 输出目录(安装目录),样例,测试按照默认配置 #configure
等待输出 Generating install / Configuring done #Generate
等待输出 Generating done cmake工程配置完成
打开VS,打开工程,工程文件目录为build目录 ,工程文件 spdlog.sln
选择ALL_BUILD项目,右键生成。等待生成完成。
选择INSTALL,右键生成。等待安装完成。即可在 output目录看到输出目录(include,lib)
设置 example 为活动项目,查看官方样例。调试查看
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
配置 CMakeLists.txt 路径,编译路径
配置 Visual Studio 编译器,平台版本。
配置 其他属性
生成完成界面
spdlog 工程目录结构如下
代码说明
设置日志输出样式
相关函数:
默认样式:[2014-10-31 23:46:59.678] [my_loggername] [info] Some message
设置日志输出样式有两种方法:
- Set the pattern string (recommended):
set_pattern(pattern_string);
- 1
- mplement custom formatter that implements the formatter interface and call
set_formatter(std::make_unique<my_custom_formatter>());
- 1
针对第一种方法:
//应用于全局所有注册的日志样式设置
spdlog::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
//应用于日志对象的样式设置
some_logger->set_pattern(">>>>>>>>> %H:%M:%S %z %v <<<<<<<<<");
//特定的接收器对象
some_logger->sinks()[0]->set_pattern(">>>>>>>>> %H:%M:%S %z %v <<<<<<<<<");
some_logger->sinks()[1]->set_pattern("..");
- 1
- 2
- 3
- 4
- 5
- 6
- 7
样式输出参数列表
flag | meaning | example |
---|---|---|
%v | The actual text to log | “some user text” |
%t | Thread id | “1232” |
%P | Process id | “3456” |
%n | Logger’s name | “some logger name” |
%l | The log level of the message | “debug”, “info”, etc |
%L | Short log level of the message | “D”, “I”, etc |
%a | Abbreviated weekday name | “Thu” |
%A | Full weekday name | “Thursday” |
%b | Abbreviated month name | “Aug” |
%B | Full month name | “August” |
%c | Date and time representation | “Thu Aug 23 15:35:46 2014” |
%C | Year in 2 digits | “14” |
%Y | Year in 4 digits | “2014” |
%D or %x | Short MM/DD/YY date | “08/23/14” |
%m | Month 01-12 | “11” |
%d | Day of month 01-31 | “29” |
%H | Hours in 24 format 00-23 | “23” |
%I | Hours in 12 format 01-12 | “11” |
%M | Minutes 00-59 | “59” |
%S | Seconds 00-59 | “58” |
%e | Millisecond part of the current second 000-999 | “678” |
%f | Microsecond part of the current second 000000-999999 | “056789” |
%F | Nanosecond part of the current second 000000000-999999999 | “256789123” |
%p | AM/PM | “AM” |
%r | 12 hour clock | “02:55:02 pm” |
%R | 24-hour HH:MM time, equivalent to %H:%M | “23:55” |
%T or %X | ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S | “23:55:59” |
%z | ISO 8601 offset from UTC in timezone ([+/-]HH:MM) | “+02:00” |
%E | Seconds since the epoch | “1528834770” |
%% | The % sign | “%” |
%+ | spdlog’s default format | “[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 %1%$ %v) (can be used only once) | [+++] Some message |
%@ | Source file and line (use SPDLOG_TRACE(…), SPDLOG_INFO(…) etc.) | my_file.cpp:123 |
%s | Basename of the source file (use SPDLOG_TRACE(…), SPDLOG_INFO(…) etc.) | my_file.cpp |
%g | Full path of the source file (use SPDLOG_TRACE(…), SPDLOG_INFO(…) etc.) | /some/dir/my_file.cpp |
%# | Source line (use SPDLOG_TRACE(…), SPDLOG_INFO(…) etc.) | 123 |
%! | Source function (use SPDLOG_TRACE(…), SPDLOG_INFO(…) etc. | see tweakme for pretty-print) my_func |
%o | Elapsed time in milliseconds since previous message | 456 |
%i | Elapsed time in microseconds since previous message | 456 |
%u | Elapsed time in nanoseconds since previous message | 11456 |
%O | Elapsed time in seconds since previous message | 4 |
自定义样式参数设置
spdlog允许自定义样式参数设置。方法样例如下:
摘自官方样例,不做说明。
#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()
{ using spdlog::details::make_unique; // for pre c++14 auto formatter = make_unique<spdlog::pattern_formatter>(); formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v"); spdlog::set_formatter(std::move(formatter));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
基础函数说明
1.设置日志等级
//设置全局注册日志等级
spdlog::set_level(spdlog::level::info); // Set global log level to info
//其他用法与设置日志样式相同
- 1
- 2
- 3
日志等级说明:
//宏定义
#define SPDLOG_LEVEL_TRACE 0
#define SPDLOG_LEVEL_DEBUG 1
#define SPDLOG_LEVEL_INFO 2
#define SPDLOG_LEVEL_WARN 3
#define SPDLOG_LEVEL_ERROR 4
#define SPDLOG_LEVEL_CRITICAL 5
#define SPDLOG_LEVEL_OFF 6
//枚举定义
enum level_enum
{ trace = SPDLOG_LEVEL_TRACE, debug = SPDLOG_LEVEL_DEBUG, info = SPDLOG_LEVEL_INFO, warn = SPDLOG_LEVEL_WARN, err = SPDLOG_LEVEL_ERROR, critical = SPDLOG_LEVEL_CRITICAL, off = SPDLOG_LEVEL_OFF, n_levels
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
2.日志打印函数
//全局注册函数使用方法,使用如下方法默认输出终端/控制台
//info(""); 类似于 printf(),默认参数设置已经完成,()内为具体消息。
//{}. 花括号为参数代表,可以定义为任意支持标准输出格式类型 spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH); spdlog::warn("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::info("Support for floats {:03.2f}", 1.23456); spdlog::info("Positional args are {1} {0}..", "too", "supported"); spdlog::info("{:>8} aligned, {:<8} aligned", "right", "left");
//其他方向,对象/节点 按照对应调用方法即可,
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.backtrace/dump使用
//函数代码来源:官方样例
//enable_backtrace(20); 打开 backtrace/dump 功能,参数为 dump个数 spdlog::enable_backtrace(20); // create ring buffer with capacity of 10 messages for (int i = 0; i < 100; i++) { //注意为设置输出等级之下的日志 // spdlog::debug("Backtrace message {}", i); // not logged.. } // e.g. if some error happened: spdlog::dump_backtrace(); // log them now!
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
backtrace/dump 会开辟一个缓冲区,将其他的等级之下的日志保存起来,在需要的时候弹出来。
4.标准输出/控制台打印
标准输出 依赖于 头文件 “spdlog/sinks/stdout_color_sinks.h” 或者 #include “spdlog/sinks/stdout_sinks.h” 区别是 是否支持对输出颜色的设置。
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
// or #include "spdlog/sinks/stdout_sinks.h" if no colors needed.
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)");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
5.基础文件输出 Basic file logger
#include "spdlog/sinks/basic_file_sink.h"
void basic_logfile_example()
{ try { auto my_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; }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
6.Rotating file
#include "spdlog/sinks/rotating_file_sink.h"
void rotating_example()
{ // Create a file rotating logger with 5mb size max and 3 rotated files auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
}
- 1
- 2
- 3
- 4
- 5
- 6
7.Dailt file
生成日期日志,每天指定时间生成对应的日志文件,也是服务系统中常用的日志,方便定位错误,日常检查
#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 daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
}
- 1
- 2
- 3
- 4
- 5
- 6
8.Log binary data in hex
// many types of std::container<char> types can be used.
// ranges are supported too.
// format flags:
// {:X} - print in uppercase.
// {:s} - don't separate each byte with space.
// {:p} - don't print the position on each line start.
// {:n} - don't split the output to lines.
#include "spdlog/fmt/bin_to_hex.h"
void binary_example()
{ auto console = spdlog::get("console"); std::array<char, 80> buf; console->info("Binary example: {}", spdlog::to_hex(buf)); console->info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10)); // more examples: // logger->info("uppercase: {:X}", spdlog::to_hex(buf)); // logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf)); // logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
9.异步日志
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"
void async_example()
{ // default thread pool settings can be modified *before* creating the async logger: // spdlog::init_thread_pool(8192, 1); // queue with 8k items and 1 backing thread. auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt"); // alternatively: // auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
10.系统日志
#include "spdlog/sinks/syslog_sink.h"
void syslog_example()
{ std::string ident = "spdlog-example"; auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID); syslog_logger->warn("This is warning that will end up in syslog.");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
11.多个日志(Logger with multi sinks - each with different format and log level)
// create logger with 2 targets with different log levels and formats.
// the console will show only warnings or errors, while the file will log all.
void multi_sink_example()
{ auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); console_sink->set_level(spdlog::level::warn); console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v"); auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true); file_sink->set_level(spdlog::level::trace); spdlog::logger logger("multi_sink", {console_sink, file_sink}); logger.set_level(spdlog::level::debug); logger.warn("this should appear in both console and file"); logger.info("this message should not appear in the console, only in the file");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
其他特性说明
spdlog还支持线程池,异步多线程写日志,线程安全日志,非线程安全日志。
Loggers
To create thread safe loggers, use the _mt factory functions.
线程安全日志 后缀为 _mt
auto logger = spdlog::basic_logger_mt(...);
- 1
To create single threaded loggers, use the _st factory functions.
非线程安全 _st
auto logger = spdlog::basic_logger_st(...);
- 1
根据项目需求来使用。
结尾
制作了简单介绍,创建与使用,其他复杂的应用还需要在实际项目中使用。最后还是使用了 glog 日志模块。主要想使用 backstrac/dump功能,结果不是预计中,项目奔溃/出错,在日志最后打印错误堆栈信息。测试时还是使用系统信号测试使用。
简单的代码片段
主要功能是,根据系统错误信号,打印错误日志,堆栈日志。其实想法是,每一个类设置对应的信号,错误输出,然后建立一个全局的错误处理。只停留于想法,没有时间做具体的实现。
#include "spdlog/sinks/rotating_file_sink.h"
void rotaing_file()
{
auto rotating_logger = spdlog::rotating_logger_mt("file_logger","logs/rotating_file.txt",1048576 * 5,3);
rotating_logger->set_pattern("[%Y-%m-%d %H:%M:%S] [%l] %! %v");
rotating_logger->enable_backtrace(20);
rotating_logger->set_level(spdlog::level::trace);
rotating_logger->debug("rotating-debug-try {} {} {}", 2019, 03, "01");
rotating_logger->info("rotating-info-try {} {} {}", 2019, 03, "01");
char * a;
memcpy(a, 0, 0);
// rotating_logger->flush();
}
void error_handle(int s)
{
if (s == SIGSEGV)
{
spdlog::dump_backtrace();
}
}
void trace_example()
{
SPDLOG_TRACE("Some trace message..{},{}",1,3.23);
SPDLOG_DEBUG("Some trace message..{},{}",1,3.23);
auto logger = spdlog::get("file_logger");
SPDLOG_LOGGER_TRACE(logger, "another trace message");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
+++ ↩︎
文章来源: blog.csdn.net,作者:何其不顾四月天,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/u011218356/article/details/104964860