如何使用google的日志库(glog)

来源:互联网 发布:网络赚钱项目有哪些 编辑:程序博客网 时间:2024/04/20 18:58

原文地址

简介

glog是google的一个应用级的日志库,这个库提供了基于C++风格的流式日志API和各种各样的帮助宏,你可以通过一个简单的流来日志一条消息,比如:
#include <glog/logging.h>int main(int argc, char* argv[]) {// 设置日志文件路径FLAGS_log_dir = "./";// 初始化日志库google::InitGoogleLogging(argv[0]);// 日志...LOG(INFO) << "Found " << num_cookies << " cookies";// 关闭日志库google::ShutdownGoogleLogging();return 0;}
glog定义了一系列的宏来简化一些常用的日志任务。你可以通过日志等级(内置)、日志条件等级来打印日志,可以使用命令行来控制日志行为,可以通过条件判断终止程序的执行,也可以定义我们自己的更详细的日志等级,当然还有更多的。这篇文章描述了glog所提供的功能支持。请注意本文所描述的并不是glog的所有特性,本文只是列举了其中最有用的部分。如果你想了解更多的功能特性,请查看src/glog目录下的头文件。

日志等级

       你可以使用以下的日志等级(日志等级从低到高):INFOWARNINGERRORFATAL。使用FATAL打印日志的时候,程序会在打印该日志后终止。需要注意的是,一个给定的日志等级日志信息不仅会记录到当前的日志等级文件,还会记录到所有比他等级低的日志文件内(就是说,WARNGING的日志不仅会打印到日志文件warnging中,还会打印到INFO日志文件中),比如FATAL的日志会打印到所有的日志文件中,包括INFOWARNINGERRORFATAL
   嘻嘻,DFATAL等级的日志会在调试(debug,没有NDEBUG这个宏的定义)模式下日志下一条FATAL的错误消息,自动把日志等级降低到ERROR等级防止程序停止。
   默认情况下,日志文件会写到/tmp/<program name>.<hostname>.<user name>.log.<severity level>.<date>.<time>.<pid>文件中(比如:/tmp/hello_world.example.com.hamaji.log.INFO.20080709-222411.10474)。默认情况下,glog会把ERRORFATAL的消息同时记录到日志文件和命令行窗口。

设置标志

    有几个标志会影响到glog的输出结果,如果你的机器已经安装了Google gflags library,那么脚本(更多的信息请查看安装包下面的INSTALL文件)会被glog自动检测到并使用,但也允许你使用命令行来设置标志。比如,如果你想启用--logtostderr标志,你可以通过下面的命令来启动你的程序:
./your_application --logtostderr=1
  如果你没有安装Google gflags library,你可以通过环境变量来设置标志,标志名称以GLOG_开始,如:
GLOG_logtostderr=1 ./your_application
  下面的标志是最常使用的:
  • logtostderr (bool, 默认是false):把日志信息打印到stderr而不是日志文件。你可以设置1、true、yes(区分大小写)使得该选项为true,设置0、false、no使得该选项为false。
  • stderrthreshold (int, 默认是2, 代表ERROR):复制所有该日志等级以上信息到stderr和文件,INFOWARNINGERRORFATAL分别对应0、1、2、3
  • log_dir (string,默认是"")如果指定该项,日志文件会写到该目录下,而不是默认的目录
  • v (int, 默认是0):显示所有小于等于m的VLOG(m)消息,是--vmodule的重写,更多信息请查看the section about verbose logging
  • vmodule (string, 默认是""):支持详细的级别。这个参数必须包含使用逗号分开的一个<module name>=<log level>列表。<module name>是一个全局通配符(如gfs*,所有以gfs开头的模块名),用来匹配文件名。<log level>是--v提供的任意值。更多请查看the section about verbose logging.
 当然glog在logging.cc还提供了其他的设置标志,你可以通过查看源码下面的DEFINE_查找更多的信息。
 你也可以在你自己的程序中通过修改全局变量FLAGS_*的值来修改标志值。大多数的设置在你设置完FLAGS_*后会即时生效的,除了那些和目标文件有关的标志。
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";


条件/频率日志

    有时候,你可能只在某种特定情况下打印日志,那么你可以使用类似下面的方法来实现:
<span style="font-size:18px;">LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";</span>
   这条消息只会在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个的日志信息:
LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
   该语句会打印前20条日志信息。


支持调试模式

   使用的调试宏仅仅在调试模式下生效,而在非调试调试模式下会编译为空,使用这些宏可以防止因为日志而带来的性能问题。
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可以使得在预期的条件不满足的情况下终止程序,类似于标准C定义的宏assert。
  assert会在不满足预设条件的情况下终止程序。和assert不同,因为不受NDEBUG的控制,所以虽然在编译模式下,但是这种检查还是会执行的。因此下面的fp->Write(x)总是会被执行。
CHECK(fp->Write(x) == 4) << "Write failed!";
      glog有很多检查相等和不相等的宏,CHECK_EQCHECK_NECHECK_LECHECK_LTCHECK_GE, and CHECK_GT。当不满足预期条件的时候,glog会日志一条包含比较的两个值的FATAL消息。需要注意的是,比较的两个值operator<<(ostream, ...)已经定义。
  你可能这样添加错误消息检查宏:
CHECK_NE(1, 2) << ": The world must be ending!";
     我们非常小心地尽量保证每个参数仅计算一次,而且确保每个合法的函数函数传参是合法的。特别是临时变量会在其声明区销毁,比如:
CHECK_EQ(string("abc")[1], 'b');
   如果一个参数是一个指针,而且而另外的一个值为NULL,编译器就会报错。为了使之可以正常工作,需要使用static_cast 来转换NULL,如:
CHECK_EQ(some_ptr, static_cast<SomeType*>(NULL));
 其实更好的方法是使用宏CHECK_NOTNULL 
CHECK_NOTNULL(some_ptr);   some_ptr->DoSomething();
  因为返回值是对应的指针类型,这点对于构造函数的初始化列表是很有用的:
struct S {S(Something* ptr) : ptr_(CHECK_NOTNULL(ptr)) {}Something* ptr_;};
  需要注意的是,因为这个原因,你不能把这个宏当做C++的流来使用。在程序终止之前,请使用上述的CHECK_EQ来日志信息。
  如果你要比较C格式的字符串,glog提供了很多大小写区分和不区分字符串比较宏: CHECK_STREQCHECK_STRNECHECK_STRCASEEQ,CHECK_STRCASENE。CASE版本的宏是指大小写区分的。在使用这些宏的时候,你可以放心地传递参数NULL,这些宏会把NULL和非NULL视为不等,而两个NULL视为相等。
  需要注意的是可能两个参数都是临时字符串,都会在整个表达式结束之后销毁(比如: CHECK_STREQ(Foo().c_str(), Bar().c_str())中的Foo和Bar返回C++格式的std::string).
  宏CHECK_DOUBLE_EQ是在一定的误差范围内检查两个浮点数是否相等。如果需要指定误差范围,使用宏CHECK_NEAR,他的第三个参数即为误差范围。

详细日志

   当你在跟踪调试很难的bug的时候,日志消息是非常重要的。然而,在日常的开发过程中,你一般希望忽略掉太详细的日志,对于这样的详细日志,glog提供了VLOG这个宏,它允许你定义自己的数字化的日志等级。--v命名选项控制着详细日志是否会被记录。
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)不会打日志。这个和内置的日志等级相反的,因为INFO是0而ERROR是2--minloglevel会记录WARNING WARNING 以上的所有等级的日志。虽然在宏VLOG和标志--v都可以指定任意一个数字,但是他们的相同的作用值的却是相反的。比如,如果你要使用VLOG(0),你得使用--v=-1或者更低的去压制他。大多情况下我们不是使用默认值的详细日志,所有这个使用的不多。宏VLOG记录的是INFO等级的日志(...)。
   一些支持的详细日志操作可以通过命令行来控制:
--vmodule=mapreduce=2,file=1,gfs*=3 --v=0
  将会:
  • mapreduce.{h,cc}打印 VLOG(2)和更低等级的日志
  • file.{h,cc}打印 VLOG(1)和更低等级的日志
  • 从“gfs”开头的文件打印 VLOG(3)和更低等级的日志
  • 从其他地方打印 VLOG(0)和更低等级的日志
  支持通配符*和?的函数,请查看command line flags。
   像一般日志一样,详细日志的也有条件宏,VLOG_IS_ON(n)。在--v等于或者大于n的时候,这个宏返回true,用法如下:
if (VLOG_IS_ON(2)) {// do some logging preparation and logging// that can't be accomplished with just VLOG(2) << ...;}
  详细日志的条件宏VLOG_IFVLOG_EVERY_N 和 VLOG_IF_EVERY_N的用法和一般日志的 LOG_IFLOG_EVERY_NLOF_IF_EVERY一样,但是提供了一个数字化的参数区分日志等级。
VLOG_IF(1, (size > 1024))<< "I'm printed when size is more than 1024 and when you run the ""program with --v=1 or more";VLOG_EVERY_N(1, 10)<< "I'm printed every 10th occurrence, and when you run the program ""with --v=1 or more. Present occurence is " << google::COUNTER;VLOG_IF_EVERY_N(1, (size > 1024), 10)<< "I'm printed on every 10th occurence of case when size is more "" than 1024, when you run the program with --v=1 or more. ";"Present occurence is " << google::COUNTER;



错误机制处理


   glog提供了一个可信的错误处理机制,在程序崩溃的情况下(因为某些特定的信号,如SIGSEGV)dump下有用的信息。这个错误处理可以通过google::InstallFailureSignalHandler()方式安装。下面是一个错误处理的输出结果示例:
*** Aborted at 1225095260 (unix time) try "date -d @1225095260" if you are using GNU date ****** SIGSEGV (@0x0) received by PID 17711 (TID 0x7f893090a6f0) from PID 0; stack trace: ***PC: @           0x412eb1 TestWaitingLogSink::send()@     0x7f892fb417d0 (unknown)@           0x412eb1 TestWaitingLogSink::send()@     0x7f89304f7f06 google::LogMessage::SendToLog()@     0x7f89304f35af google::LogMessage::Flush()@     0x7f89304f3739 google::LogMessage::~LogMessage()@           0x408cf4 TestLogSinkWaitTillSent()@           0x4115de main@     0x7f892f7ef1c4 (unknown)@           0x4046f9 (unknown)
  默认情况下,错误处理会把信息输出到标准错误输出,你可以使用InstallFailureWriter()自行改变输出位置。


总结

     使用GLog时,下载好glog库,在该压缩包里面直接有一个Visual Studio的工程,打开直接编译即可生成我们所需要的静态链接库,这样使用的时候,包含头文件以及链接该静态库即可happy地使用glog了。
0 0
原创粉丝点击