最近需要调试一个算法程序,由于算法程序涉及到大量请求的调度,而且出现bug的时间也不确定。为了复现程序(C++)的bug,并收集相应的信息,我需要不断地在文件里输出相应的信息。传统的借助C++文件流的方法,不仅繁琐复杂,而且效率低下,总之就是不够优雅。那么如何优雅地获取调试信息呢?答案很简单,就是使用专业的日志库,不仅可以为调试信息输出时间戳,而且可以设置日志输出级别,总之就是专业、大气、上档次。当然,我们不会自己造轮子,因为开源社区有大量优秀的C++日志库,二话不说撸GitHub!GitHub可是个好地方,这里面个个都是人才,说话又好听。
下面我们来看一下GitHub上有什么日志库的轮子吧:
不用说肯定是选第一个咯——spdlog,名字响亮而且文雅,够大气,就是你了!严肃地说,从标签可以看出spdlog使用C++ 11编写,而且只需要头文件就可以使用spdlog库,最重要的是Fast,这一点足可以作为使用它的理由,因为我们一般不希望日志对程序性能产生较大的影响。二话不说,开始撸代码!
打开README,果然用法很简单,堪称傻瓜式用法:
输出不同级别的日志:
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);
输出到日志文件:
auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
my_logger->info("spdlog is very easy to use!");
搭配C++ 11使用简直绝配,就是那么简单,而且我们不用再管文件打开之后忘记关闭的问题了。
当然我的调试需求也被轻松搞定了:由于涉及到大量的调试信息,而且调试信息较长,这样就会导致日志文件过大。文件过大很明显的缺点就是可能会导致磁盘空间不够,而且使用编辑器打开也特别慢,这将使得阅读日志变得十分困难。具体如何解决的呢?spdlog有一个日志类型叫做rotating_logger_mt
,看到名字你应该会恍然大悟。使用这个日志类型,我们可以设置单个日志文件的大小,轮转日志的数量。这样的话,当一个文件写到足够大小就会写下一个文件,直到写够足够数量就会覆盖第一个文件再开始写日志,简直完美解决我的问题。
下面是示例代码,看起来特别简单,第一个参数是日志的名字,第二个参数是文件名,第三个参数是文件的大小。最后一个参数是文件数量,当文件达到指定大小5MB时,便会生成myfilename.1、myfilename.2 ...
#include <iostream>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/rotating_file_sink.h" // support for rotating file logging
int main(int argc, char* argv[]) {
try {
// create a file rotating logger with 5mb size max and 3 rotated files
auto file_logger = spdlog::rotating_logger_mt("file_logger", "myfilename", 1024 * 1024 * 5, 3);
for (int i = 0; i < 1024 * 1024 * 5 * 4; i++)
file_logger->info("This is a rotating logger: #{}", i);
} catch (const spdlog::spdlog_ex& ex) {
std::cout << "Log initialization failed: " << ex.what() << std::endl;
}
}
我这里写了几个Demo,供大家参考使用:spdlog_demo
参考资料
- spdlog的GitHub仓库:https://github.com/gabime/spdlog
- Demo的GitHub仓库:https://github.com/Fibird/spdlog_demo
- spdlog的wiki地址:https://github.com/gabime/spdlog/wiki