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

原文地址

简介

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_IF VLOG_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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值