基本构成
struct log_msg
日志消息,用来存储日志信息的结构体,里面存了日志器名称、日志级别、创建时间、线程id和日志内容等信息。
class logger
日志器,直接面向用户的日志类,调用api输出日志。
class sink
输出器,负责将日志文本输出的类。这个类本身是个抽象类,spdlog基于他派生出了各种类型的输出器,例如输出到控制台的、输出到文件的。
一个logger可以拥有多个sink。也可以多个logger共享一个sink。
class formatter
格式化器,负责将log_msg
对象转换成最终要输出的字节数组。
每一个sink都拥有一个formatter。
spdlog维护了一个全局注册表,里面存储着全局共享的数据,当创建logger和sink时,默认使用的就是注册表里的formatter。
基本工作流程
当用户通过logger实例的info()、wram()等函数输出日志后,logger会使用fmt::format将用户传入的文本中的占位符”{}”替换成对应的参数,随后创建一个log_msg实例并传递给sink,sink输出前会调用formatter,根据指定的日志格式,对log_msg进行格式化,转换成字符数组后输出。
用法
(一)使用默认的日志器进行简单输出
spdlog提供了默认的全局日志器,使用下面的方法直接调用就可以了。
例子:
1 | spdlog::debug("Hello"); |
(二)使用宏输出日志
用宏输出日志可以自动添加当前文件名称和代码行号等信息,方便调试。
spdlog默认情况下关闭了相关的宏,需要在头文件”spdlog.h”引入前,定义指定的宏开启该功能。使用方法如下
1 |
其中SPDLOG_LEVEL_INFO
代表最低有效等级为INFO,低于该等级的日志宏将会不生效。spdlog为每一个日志级别都定义了对应的宏,可以按需求设置。这个宏只需要在mian()函数所在的文件定义一次就可以了。
1 |
使用宏输出日志时,需要显式指定用于输出的日志器,可以使用函数spdlog::default_logger()
获取默认日志器的智能指针,也可以使用自己创建的日志器。
例子:
1 | SPDLOG_LOGGER_INFO(spdlog::default_logger(), "Hello world"); |
(三)自定义日志格式 和 设置日志有效级别
spdlog最终输出的日志格式是通过formatter进行格式化的,通过替换不同的formatter,即可实现对日志格式的控制。
spdlog提供了非常简易的方式配置日志格式,不需要我们手动构造formatter实例,只需要调用函数set_pattern("..")
,并传入需要的格式化标记字符串即可。
例如,设置全局所有日志器的输出格式可以使用下面的方法。
1 | spdlog::set_pattern("[%H:%M:%S][%n][thr %t][%s:%!():%#] %v"); |
这里摘抄一些比较常用的标记符,其他的可以去github看官方的wiki。
符号 | 作用 |
---|---|
%v | 用户的日志文本 |
%t | 线程id |
%P | 进程id |
%n | 日志器名称 |
%l | 日志级别 |
%x | 简略的日期 MM/DD/YY |
%X | 24小时制的时间,显示时分秒 |
%s | 显示日志所在的文件的名称。需要使用spdlog提供的宏输出日志才有效果 |
%! | 显示日志所在的函数的名称。需要使用spdlog提供的宏输出日志才有效果 |
%# | 显示日志所在的行号。需要使用spdlog提供的宏输出日志才有效果 |
需要注意的是spdlog::set_pattern()
函数修改的是全局注册表里登记过的所有日志器。下一节会介绍到相关的东西。
spdlog还提供了设置有效日志级别的接口,低于指定级别的日志信息将会被忽略,不被输出。
例子:
1 | // 设置全局默认日之器的输出级别 |
每一个logger和sink都是可以单独设置日志格式和日志级别的,具体做法后面介绍。
(四)输出日志到文件
spdlog提供了一些工厂函数可以很方便的创建输出到文件的日志器。
例子:
1 | // 最基本的输出到文件的日志器 |
这些工厂函数都有个”_mt”后缀,这个后缀是 multi-thread 的缩写,代表该函数创建的日志器是多线程安全的。相反的,spdlog也提供了非线程安全的版本,只需要把后缀”_mt”改成”_st”即可,该版本去掉了所有的锁,用于单线程下获得更高的输出效率。
使用spdlog提供的工厂函数创建的日志器,会自动在spdlog维护的全局注册表中进行注册,使用spdlog::get("[logger_name]")
函数,可以在程序的任何地方获取相同的日志器。
1 | auto file_logger = spdlog::basic_logger_mt("[logger_name]", "[file_name]"); |
(五)组装自定义的日志器
如果想要更加灵活的日志器,例如一个日志器按日志等级输出到终端或者不同的文件、多个日志器输出到同一个文件上、不同的文件使用不同的日志格式等等,都需要自己手动组装日志器来实现。
在命名空间spdlog::sinks
下提供了大量预设的sink实现,可以直接使用这些预设的实现组合自己的logger。只需要引入对应的头文件即可。
1 |
创建一个输出到多个文件和控制台的logger。
例子:
1 | // spdlog完全使用c++11标准进行开发,logger、sink、formatter等实例对象均使用std::shared_ptr进行内存管理。 |
创建输出到同一个文件的不同logger
例子:
1 | auto file = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/file"); |
每一个logger和sink的实例都提供了接口手动设置日志级别和日志格式。
例子:
1 | // logger设置日志格式。 |
手动组装的日志器如果想要使用spdlog::get("[logger_name]")
在任意地方获取,那就需要手动将创建好的日志器加入到spdlog的注册表中,方法也很简单,只需一行代码。
1 | spdlog::register_logger(mix_logger); |
(●’◡’●)