对于线上服务,打日志至关重要,通过日志可以进行事件定位、debug,有时也会通过收集日志实现追溯、监控、特征采集等工作。
1. spdlog简介
spdlog github
一个开源的C++日志库,快速便捷,使用了fmt作为格式化工具。
2. spdlog 基本用法
在使用spdlog时,我们需要明确几个概念
- sink: 描述日志如何具体落地的类,例如:stdout_sink/stderr_sink 落日志到标准输出/错误输出, rotating_file_sink 落日志到滚动文件, 还有落日志到kafka、mongodb等等。记录在spdlog/sinks目录下。
- logger: 由单个或多个sink组成的日志类。组合了sink, 由同步和异步两大类。
- logger factory: 创建logger的工厂类,获取logger的同时,会把<name, logger>记录到全局的registry中。
2.1 默认logger
直接通过spdlog类调用对应的记录接口时,使用的是默认的logger. 可以看到默认的logger是 ansicolor_stdout_sink_mt,当然registry也提供了修改默认logger的方法.
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");
2.2 日志级别
spdlog提供了以下几种日志级别:
enum level_enum : int {
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
};
2.3 创建logger
sink -> logger -> factory
sink文件中,同时也提供了创建该sink的方法,我们需要在创建方法中传入工场factory类型和实例初始化参数。例如创建文件异步sink:
// auto logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
auto logger = spdlog::basic_logger_mt<spdlog::async_factory>("basic_logger", "logs/basic-log.txt");
logger->info("file log");
// spdlog::get("basic_logger")->info("file log");
同步和异步的区别在于,异步logger会把日志放入queue中,让线程池中的线程取出进行处理(调用sink_it_),同步logger则是直接调用sink_it_接口。异步日志根据队列满时的动作又有阻塞、非阻塞一些模式,区别是队列满时是否等待、丢弃日志。
using async_factory = async_factory_impl<async_overflow_policy::block>;
using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;
创建之后logger可以直接通过实例调用,或者通过spdlog::get(logger_name)获取实例后调用。
2.4 日志格式
创建出来的logger可以自定义日志格式,详细的参数可以参考: 日志格式参数
3. 封装成日志宏
在实际服务中,我们通常实在初始化日志组件后,通过简单的几个宏来调用对应的日志实例进行日志打印,简洁且方便替换。下面给出一种可用的封装。提供了C风格给python风格两种形式。头文件额外包含:
#include <thread>
#include <spdlog/fmt/bundled/printf.h>