工作有一段时间了,总是在忙碌和无所事事中矛盾着,今天据说台风17级,正好休息,于是整理一下glog。
在公司管理日志用glog比较多,因为它开源,而且确实方便。官方文档在这里:http://google-glog.googlecode.com/svn/trunk/doc/glog.html 。按照个人理解翻译一下,翻译中可能会有个人理解,所以不保证原汁原味(不过尽量保持),也因水平有限,欢迎拍砖。
简介(Introduction)
Google glog是一个实现应用级别日志的开源库,这个库提供了基于C++流风格的日志接口和许多有用的宏。要打出一个日志信息,只要和C++流类似的把信息输出到LOG()就可以了,哈哈,很容易吧?就和C++中使用cout一样!例如:
#include
int main(int argc, char* argv[]) {
// Initialize Google's logging library.
google::InitGoogleLogging(argv[0]);
// ...
LOG(INFO) << "Found " << num_cookies << " cookies";
}
为了简化许多普遍的日志工作,glog定义了一系列宏。我们可以根据严重性等级打出日志,可以在命令行控制日志行为,可以按条件打出日志,也可以在期望的条件没有达到时退出程序,还可以引进自己的日志等级,等等。本文档介绍glog支持的功能。但是注意本文档并未介绍该库中所有的功能,仅介绍大多数有用功能。如果想了解更多常用功能的话,可以查看src/glog目录下的头文件。(补充一句:对于大多数开源工具,查看头文件虽然不能了解底层实现,但却是掌握接口使用和库中提供的功能的快捷通道。)
严重性等级(Severity Level)
我们可以指定INFO、WARNING、ERROR、FATAL中的一种等级打出日志(严重性依次递增),以FATAL打出日志会在信息输出后终止程序。需要注意的是,高级别的日志不仅会输出在对应级别的日志文件中,也会输出在低级别的日志文件中。例如:一个ERROR级别的日志会同时输出在ERROR、WARNING、INFO对应的日志文件中。
DFATAL级别的日志会在debug模式下打出一个FATAL级别的错误,在产品中,它通过自动降级为ERROR从而避免程序中断。
除非特别指定,否则glog会把日志信息输出到"/tmp/
设置参数(Setting Flags)
有几个参数会影响glog的输出行为。如果你的电脑上安装了Google gflags library,那么配置脚本(可以查看包中的安装文件获取更多关于该脚本的详细信息)会发现和适用它,从而允许你在命令行传入参数。例如,如果你想开启参数--logtostderr,那么你可以按如下命令行启动自己的应用:
./your_application --logtostderr=1
如果你没有安装Google gflags library,那么你可以通过设置环境变量设置这些参数,在参数名前加上 "GLOG_"就可以了。例如:
GLOG_logtostderr=1 ./your_application
以下是常见的参数:
logtostderr
(bool
, default=false
)
把信息输出到标准错误而非文件,默认值为false。stderrthreshold
(int
, default=2, which is ERROR
)
严重性级别在该值以上的日志信息同时写入文件和标准错误。
严重性等级对应关系:INFO、WARNING、ERROR、FATAL一次为0、1、2、3。
log_dir
(string
, default="")
日志信息记录文件,默认为空。
v
(int
, default=0)
对于所有用VLOG(m)打出的日志,仅在m的值小于该参数的值时才进行输出,该值可能被vmodule覆盖,默认为0。
vmodule
(string
, default="")
分模块儿设置VLOG(m)日志的输出。参数格式为以逗号分隔的 你还可以通过在程序中设置全局变量“FLAGS_*”调整参数。除了和目标文件有关的设置外,多数设置会在修改完FLAGS_*后立即生效。例如,你可能试图在调用google::InitGoogleLogging前设置FLAGS_log_dir
,这里是个例子:
LOG(INFO) << "file";
// Most flags work immediately after updating values.
FLAGS_logtostderr = 1;
LOG(INFO) << "stderr";
FLAGS_logtostderr = 0;
// This won't change the log destination. If you want to set this
// value, you should do this before google::InitGoogleLogging .
FLAGS_log_dir = "/some/log/directory";
LOG(INFO) << "the same file";
条件日志(Conditional/Occasional Logging)
有时,你可能想仅在某些条件满足的情况下才记录日志信息,可以使用如下宏完成条件日志:
LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
只有当num_cookies > 10,该日志才会输出。如果某一行会被执行多次,在某些区间内输出信息可能非常有用。
LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
上面这条语句在该命令第1,11,21……次被执行时输出日志。google::COUNTER记录当前执行的次数。
以上两类情况可以通过以下宏合并在一起使用:
LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER
<< "th big cookie";
除了在每第n次时输出日志,也可以限制前n次出现时输出日志:
LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
该命令在前20次执行时输出日志信息。
支持debug模式(Debug Mode Support)
debug模式的特定的宏只在debug模式下生效,在非debug模式下编译中不生成任何信息。使用该宏可以避免因过多日志导致应用速度减慢。
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宏(Check Macros)
在程序中周期性地检查期望出现的情况,从而尽早的发现错误是一种非常好的习惯和方法。CHECK宏提供了一种在某种条件不满足时退出程序的机制,和标准C库中定义的assert类似。CHECK宏在条件非真时退出程序,和assert不同的是,CHECK不受NDEBUG的约束,因此,下例中的fp->Write(x)总是会被执行:
CHECK(fp->Write(x) == 4) << "Write failed!";
有很多进行比较的宏:CHECK_EQ
, CHECK_NE
, CHECK_LE
, CHECK_LT
, CHECK_GE
, 和CHECK_GT(宏的意义根据字面意思应该很好理解,比如EQ是equal,GT是greater than等)。这些宏比较两个值,当结果和期望值不同时,输出一个FATAL级别的日志,该日志内容包含这两个值,因此,对比较的类型,必须定义了operator << (ostream, ...)。
举例:
CHECK_NE(1, 2) << ": The world must be ending!";
CHECK_EQ(string("abc")[1], 'b');
如果出现类型不一样的情况,可以用static_cast进行类型转换:
CHECK_EQ(some_ptr, static_cast(NULL));
该例子中比较some_ptr是否为NULL。
然后更好的比较方法是使用宏CHECK_NOTNULL:
CHECK_NOTNULL(some_ptr);
some_ptr->DoSomething();
由于该宏返回该指针,所以在构造函数的初始化列表中非常有用:
struct S {
S(Something* ptr) : ptr_(CHECK_NOTNULL(ptr)) {}
Something* ptr_;
};
如果要比较两个C类型的字符串是否相等,可以使用CHECK_STREQ
, CHECK_STRNE
, CHECK_STRCASEEQ
,CHECK_STRCASENE,其中,带有CASE的表示大小写不敏感。像这些宏传入参数时,可以传入NULL,比较时,NULL和任何非NULL的字符串不相等,任意两个NULL相等。
CHECK_DOUBLE_EQ检查两个浮点数是否相等,允许一个小范围的误差。CHECK_NEAR接受第三个浮点数作为参数,以指定误差允许的范围。