使用方法

spdlog是基于C++ 11的日志组件,它非常轻量,使用时你仅仅需要引入头文件就可以了。

spdlog下载链接
或使用命令下载

1
wget https://github.com/gabime/spdlog

下载完成后,将includ/spdlog目录单独拷贝到自己的工程目录,g++编译文件头路径添加include/spdlog即可,spdlog一级目录为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-bash-4.2$ ll ../spdlog/
total 56
-rw-rw-r--. 1 centos centos 988 Dec 30 07:43 appveyor.yml
drwxrwxr-x. 2 centos centos 148 Dec 30 07:43 bench
drwxrwxr-x. 2 centos centos 116 Dec 30 07:43 cmake
-rw-rw-r--. 1 centos centos 11996 Dec 30 07:43 CMakeLists.txt
drwxrwxr-x. 2 centos centos 66 Dec 30 07:43 example
drwxrwxr-x. 3 centos centos 20 Dec 30 07:43 include
-rw-rw-r--. 1 centos centos 661 Dec 30 07:43 INSTALL
-rw-rw-r--. 1 centos centos 1142 Dec 30 07:43 LICENSE
-rw-rw-r--. 1 centos centos 4682 Dec 30 07:43 meson.build
-rw-rw-r--. 1 centos centos 1773 Dec 30 07:43 meson_options.txt
-rw-rw-r--. 1 centos centos 12669 Dec 30 07:43 README.md
drwxrwxr-x. 2 centos centos 110 Dec 30 07:43 scripts
drwxrwxr-x. 2 centos centos 125 Dec 30 07:43 src
drwxrwxr-x. 2 centos centos 4096 Dec 30 07:43 tests
-bash-4.2$

修改CMakeLists.txt文件,增加头文件搜索路径

1
2
3
4
5
6
INCLUDE_DIRECTORIES(
/usr/include/
${PROJECT_SOURCE_DIR}/src/
${PROJECT_SOURCE_DIR}/include/
${PROJECT_SOURCE_DIR}/include/spdlog/
)

线程安全

命名空间 spdlog:: 下面的大多数方法是线程安全的。已知以下三个是线程不安全的,使用时请注意:

1
2
3
void spdlog::set_pattern(const std::string&);
void spdlog::set_formatter(formatter_ptr);
void spdlog::set_error_handler(log_err_handler);

日志对象的大部分方法也是线程安全的,除了:

1
2
3
void spdlog::logger::set_pattern(const std::string&);
void spdlog::logger::set_formatter(formatter_ptr);
void spdlog::set_error_handler(log_err_handler);

_mt的意思是multi thread(速度稍微慢一点点,考虑了多线程并发),_st的意思是single thread(速度较块)。所有以_mt结尾的SINK都是线程安全的,以_st结尾的则不是。

使用规则示例

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include "spdlog/spdlog.h"
#include <iostream>

// 多线程的基于控制台(stdout)的日志记录器,支持高亮。类似的stdout_color_st是单线程版本
auto console = spdlog::stdout_color_mt( "console" );
// 基于文件的简单日志
auto logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt");
// 基于滚动文件的日志,每个文件5MB,三个文件
auto logger = spdlog::rotating_logger_mt("file_logger", "myfilename", 1024 * 1024 * 5, 3);

// 定制输出格式
spdlog::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");

// 多个日志器共享SINK
auto daily_sink = std::make_shared<spdlog::sinks::daily_file_sink_mt>("logfile", 23, 59);
// 下面几个同步日志器共享的输出到目标文件
auto net_logger = std::make_shared<spdlog::logger>("net", daily_sink);
auto hw_logger = std::make_shared<spdlog::logger>("hw", daily_sink);
auto db_logger = std::make_shared<spdlog::logger>("db", daily_sink);

// 一个日志器使用多个SINK
std::vector<spdlog::sink_ptr> sinks;
sinks.push_back( std::make_shared<spdlog::sinks::stdout_sink_st>());
sinks.push_back( std::make_shared<spdlog::sinks::daily_file_sink_st>( "logfile", 23, 59 ));
auto combined_logger = std::make_shared<spdlog::logger>( "name", begin( sinks ), end( sinks ));
spdlog::register_logger( combined_logger );

// 异步
// 每个日志器分配8192长度的队列,队列长度必须2的幂
spdlog::set_async_mode(8192);
// 程序退出前清理
spdlog::drop_all();

// 注册日志器
spdlog::register_logger(net_logger);
// 注册后,其它代码可以根据名称获得日志器
auto logger = spdlog::get(net_logger);

// 记录日志
// 设置最低级别
console->set_level(spdlog::level::debug);
console->debug("Hello World") ;
// 使用占位符
console->info("Hello {}" ,"World");
// 带格式化的占位符:d整数,x十六进制,o八进制,b二进制
console->warn("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
// 带格式化的占位符:f浮点数
console->info("Support for floats {:03.2f}", 1.23456);
// 左对齐,保证30字符宽度
console->error("{:<30}", "left aligned");
// 指定占位符位置序号
console->info("Positional args are {1} {0}..", "too", "supported");

// 记录自定义类型,需要重载<<操作符
#include <spdlog/fmt/ostr.h>
class Duck{}
std::ostream& operator<<(std::ostream& os, const Duck& duck){
return os << duck.getName();
}
Duck duck;
console->info("custom class with operator<<: {}..", duck);

输出格式

spdlog默认的输出格式为:

1
[2014-31-10 23:46:59.678] [info] [my_loggername] Some message

要定制输出格式,可以调用:

1
2
3
spdlog::set_pattern(pattern_string);
// 示例
spdlog::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");

或者实现自己的格式化器:

1
spdlog::set_formatter(std::make_shared<my_custom_formatter>());

Pattern说明

输出格式的Pattern中可以有若干 %开头的标记,含义如下表:

flag meaning example
%v 实际需要被日志记录的文本,如果文本中有{占位符}会被替换 “my log test content”
%t 线程标识符 “123”
%P 进程标识符 “234”
%n 日志记录器名称 “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示例

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include "spdlog/spdlog.h"
#include "spdlog/sinks/daily_file_sink.h"
#include <memory>

#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"

namespace spd = spdlog;

using namespace std;

int main(int argc, char **argv)
{
//创建文件名类似于: daily_log_2018-01-17_10-27.txt,如果程序不退出的话,就是每天2:30 am创建新的文件
{
auto console= spd::daily_logger_mt("maitianPT", "./daily_log.txt", 2, 30);
//写入文档
console->info("test daily info 提示信息");
console->warn("test daily warn 警告");
console->error("test daily error 错误");
console->critical("test daily critical 致命");
}

// 打印到控制台的信息,不同日志级别,颜色不同
{
spdlog::info("Welcome to spdlog!");
spdlog::error("Some error message with arg: {}", 1);

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("{:<30}", "left aligned");

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");
}


// Set the default logger to file logger,创建普通日志文件
auto file_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt");
spdlog::set_default_logger(file_logger);
for (int i = 0; i < 1000; i ++)
{
file_logger->info("Test File Logger {}", i);
}

return 0;
}