程序跑着跑着出错了,自然就要去看日志文件,研究研究是哪里出错了。同时,记录日志也不能太慢了,速度总是十分重要的。Spdlog,也就是 Speed Log 的缩写,这个连名字都带着速度的 C++ 日志库,应该会让你满意。

C++

简介

Spdlog,是在 Github 上由 gabime 开源的 C++ 日志库,代码仓在
https://github.com/gabime/spdlog,目前版本为 1.6.1。Spdlog 以速度著称,且是 Header-Only 的,使用方便,兼容多个平台。Spdlog 还具有:格式化、异步模式、单线程/多线程、丰富的日志输出目标、运行时日志级别修改、Backtrace记录等,功能丰富,可以满足绝大多数场景的需求。

Spdlog日志库

安装

可以使用 Header-Only 的方式,把源码复制到项目的编译树中,并使用 C++11 的编译器编译。

也可以使用静态库的方式,先对 spdlog 编译后再链接到项目代码中:

git clone https://github.com/gabime/spdlog.git cd spdlog && mkdir build && cd build cmake .. && make -j

Spdlog支持的平台广泛,包括:

  • Linux, FreeBSD, OpenBSD, Solaris, AIX
  • Windows (msvc 2013+, cygwin)
  • macOS (clang 3.5+)
  • Android

也可以使用包管理的方式直接安装,如使用 Hombrew

brew install spdlog

而在 Fedora 上可以使用yum等

yum install spdlog

示例

以下给出 Spdlog 的一个基本使用例子:

#include "spdlog/spdlog.h" #include "spdlog/sinks/basic_file_sink.h" int main() { spdlog::info("Welcome to spdlog!"); spdlog::warn("Easy padding in numbers like {:08d}", 12); spdlog::error("Positional args are {1} {0}..", "too", "supported"); }

Spdlog使用了 fmt 库进行日志的格式化,可以直接调用 info、warn 等函数,使用默认的记录器进行日志输出。

日志级别和格式都是可以在运行时修改的,使用 set_level 和 set_pattern 函数进行:

spdlog::set_level(spdlog::level::debug); spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");

Spdlog 支持多种日志输出目标,包括命令行的 stdout 和 stderr、基本文件、轮转文件、每日更新的文件、POSIX 的 syslog、systemd、Windows 的 Debug等。不同的输出目标都需要包含对应的头文件,并使用对应的工厂构建函数。

Spdlog 支持单线程和多线程的日志记录器,其中多线程版本的是线程安全的。单线程版本的工厂函数以 _st 结尾,而多线程版本则以 _mt 结尾。

可以使用不同输出目标和不同线程版本的 logger 来进行定制化记录。如

#include "spdlog/sinks/rotating_file_sink.h" auto file_logger = spd::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3);

定义了一个多线程轮转文件的 logger,名字为 file_logger,输出文件路径为 logs/mylogfile,最大大小为 5MB,最多保留 3 个文件。而

#include "spdlog/sinks/daily_file_sink.h" auto daily_logger = spdlog::daily_logger_st("daily_logger", "logs/daily", 14, 55);

则定义了一个单线程的每日更新文件的 logger,名字为 daily_logger,输出路径为 logs/daily,且在每天的 14:55 分创建新的日志文件。

更多

  • Spdlog 支持对于 Backtrace 的存储,可以在缓存记录一定数量的日志消息,并在需要时输出;

spdlog::enable_backtrace(32); ... spdlog::dump_backtrace();

  • Spdlog 支持异步模式,使用预设的线程池进行异步日志记录,可以提升多线程的速度;

auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");

  • Spdlog支持 logger 的中心化注册,方便 logger 的引用;

spdlog::register_logger(some_logger); auto logger = spdlog::get("logger1");

  • Spdlog 性能优越,在性能测试中,进行了100万次循环测试,其中:单线程的基本文件 logger 达到每秒 5,777,626(约578万)次,平均每条消息耗时 0.17微秒,轮转文件和每日更新文件也得到了同样的性能;而在10个线程竞争同一个文件时,也能得到每秒 1,659,613(约166万)次的性能;使用10个线程的异步模式则能达到每秒 2,682,285(约268万)次。

Spdlog极致快速

总结

Spdlog 性能优越,功能丰富,内置支持十余种输出目标,支持单线程/多线程和异步,另外有注册功能和 Backtrace 记录等方便使用的功能,使得 Spdlog 能够适用于绝大多数的日志记录场景。

Spdlog 采用 Header-Only 的方式设计,方便使用;代码格式标准,结构清晰,模块化程度高,代码质量高;项目测试和性能测试齐全,编译支持完善;目前社区也比较活跃,是一个值得学习和参与的开源项目。