自己原本想写一个关于日志记录的库文件以用于加速项目开发与调试,无意中了解到Google的日志模块Glog,特找来学习一下。
Google Logging Library
glog托管在Github,可以自行下载,适用于多平台的操作系统,是用C++实现的应用程序级别的日志库,可以下载下来直接使用,非常方便。
官方使用代码示例
#include <glog/logging.h>
int main(int argc, char* argv[])
{
// Initialize Google's logging library.
google::InitGoogleLogging(argv[0]);
// ...
LOG(INFO) << "Found " << num_cookies << " cookies";
}
glog定义了一系列的宏来简化许多通用的日志任务。可以通过严重等级来记录日志,可以通过命令行控制日志行为,基于条件式的日志记录,甚至当条件不满足可以中止程序。也可以在其中引入自己的更细致的日志级别。可以在src/glog源码目录中找到关于glog的更详细的特性描述。
严重等级 (Severity Level)
严重等级:
- INFO
- WARNING
- ERROR
- FATAL
(按严重等级依次递增)
记录一条FATAL日志后会导致程序中止。
DFATAL 日志会在DEBUG模式下记录一条FATAL日志,但可以避免程序中止,可以有效地放到最终的发布版程序中,DFATAL会自动地降级为ERROR.
示例
如下一段代码
#include "stdafx.h"
#include <glog/logging.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "libglog.lib")
int _tmain(int argc, _TCHAR* argv[])
{
// Initialize Google's logging library
google::InitGoogleLogging("test");
google::SetLogDestination(google::INFO, "./");
char str[] = "hello google log";
LOG(INFO) << "Found" << google::COUNTER << endl;
LOG(INFO) << str;
LOG(WARNING) << "warning test" << endl;
LOG(ERROR) << "error test" << endl;
system("pause");
return 0;
}
运行后在程序目录下产生了一个默认以精确到毫秒级的时间为日志名的文件20171003-211344.1942,文件内容如下:
Log file created at: 2017/10/03 21:13:44
Running on machine: JUN-PC
Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg
I1003 21:13:44.305011 6936 glogtestproj.cpp:20] Found0
I1003 21:13:44.321012 6936 glogtestproj.cpp:21] hello google log
W1003 21:13:44.321012 6936 glogtestproj.cpp:23] warning test
E1003 21:13:44.325011 6936 glogtestproj.cpp:24] error test
可以看到,每条日志记录了日志等级(类型可以自定义添加),日志时间,记录日志的线程号,记录日志的源文件和行号,然后就是具体的日志信息。基本上非常齐全了,足够一般项目中常用的调试任务使用了。
设置标志
当Google_gflags_library安装好后 configure 脚本会自动检测到,用户可以通过命令行传入 flags参数,比如,想要打开–logtostderr 开关,可以通过命令行调用程序:
./your_application --logtostderr=1
即使没有安装Goolge_gflags_library库,也可以通过前置GLOG_ 宏来设置相关标志,如:
GLOG_logtostderr=1 ./your_application
常用的标志有:
logtostderr(bool, default=false)
stderrthreshold(int, default=2,->ERROR)
minloglevel(int, default=0,->INFO)
log_dir(string, default="")
v(int, default=0)
vmodule(string, default="")
条件日志
当有时希望满足某个条件时再记录日志,那么条件日志宏则非常有用:
LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
当变量num_cookies大于10,则记录日志“Got lots of cookies”到日志。
通知日志
比如循环中想要每隔一写循环次数记录一条状态日志,可以这样实现 :
LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
每当上面这行词句执行的第1st, 11th, 21st都会输出一条日志记录。
条件日志和情景日志的组合
例如:
LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the "
<< google::COUNTER
<< "th big cookie";
前N次场景:
LOG_FIRST_N(INFO, 20) << "Got the "
<< google::COUNTER
<< "th cookie";
调试模式支持
高效的调试模式日志只在调试模式下有效,保证产品不会因为大量的日志记录而影响性能,降低速度。
DLOG(INFO) << "Found cookies";
DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
DLOG_EVERY_N(INFO, 10) << "Got the "
<< google::COUNTER
<< "th cookie";
校验宏 (CHECK Macros)
经常在程序中校验预期的条件来尽可能早地检测错误是一个非常好的习惯。CHECK宏的作用非常类似于标准C语言库中的 assert 宏。
不同于assert的地方在于,例如以下程序:
CHECK(fp->Write(x) == 4) << "Write failed!";
代码中的fp->Write(x)
总是会得到执行。
类似的宏还有:
- CHECK_EQ
- CHECK-NE
- CHECK-LE
- CHECK-LT
- CHECK-GE
- CHECK-GT
冗余日志(Verbose Logging)
我们经常在项目中调试一个流程需要大量的日志,而通常项目流程调试通过后这些日志往往是无用的,同时有不希望将其删除,以便以后随时可以再次调试相关流程,这时,冗余日志就会显得非常有用。
VLOG(1) << "I'm printed when you run the program with --v=1 or higher";
VLOG(2) << "I'm printed when you run the program with --v=2 or higher";
VLOG日志中冗余度越低的日志就越容易被记录下来,比如:
使用 --v==1 参数,则VLOG(1)就会被记录而VLOG(2)则不会被记录。和严重等级(SEVERITY LEVEL)刚好相反。
更多关于glog的使用和特性,请参阅/doc/glog.html
文档和相关源代码,glog真是一个非常优秀的日志库,只要你能想到的需求,它基本都非常优雅地实现了,非常实用。