怎么使用Google Logging Library (glog)

介绍

Google glog 是一个提供程序程序级的日志库. 这个库提供了c++风格的日志API和一系列的帮助宏. 你能够用简单的方式来记录日志,类似LOG(<一个特定的 severity level>), e.g.

#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";
}

Google glog定义了一系列能简化许多常见的logging任务的宏. 你能够记录严格等级的消息、从命令行控制logging行为、基于条件的日志、当预期条件不满足时退出程序、引入你自己的详细的日志级别,等等。 这篇文档描述了由glog提供的功能.但请注意,这篇文章并没有描述这个库全部的特性.如果你想找到不常见的特性,请看这个目录下的头文件: src/glog .

严重性等级

你可以指定下列严重性级别中的一个: INFO, WARNING, ERROR, 和FATAL. 记录一个 FATAL 消息将终止程序(在消息被记录之后). 要注意的是一个指定严重性级别的消息并不仅仅记录在当前严重性等级的日志文件中,并且记录于所有较低严重性等级的日志中. 比如: 一个严重等级为 FATAL 的消息将被记录在 FATAL, ERROR, WARNING, 和INFO日志中.

DFATAL 严重性记录一个 FATAL 错误在调试模式中 (i.e., 这里没有 NDEBUG 的宏定义), 避免but avoids halting the program in production by automatically reducing the severity to ERROR.

除非另行指定, glog 将把日志写到 ”

/tmp/<program name>.<hostname>.<user name>.log.<severity level>.<date>.<time>.<pid>

e.g:

/tmp/hello_world.example.com.hamaji.log.INFO.20080709-222411.10474

. 默认情况下, glog 对于ERROR和FATAL级别的日志信息,除了会写入文件外还会输出到standard error (stderr).

设置参数

有些参数会影响glog的输出行为. 如果 Google gflags library 已经被安装, 则configure 脚本 (详情看INSTALL ) 会自动发现和使用它, 并允许你通过命令行参数控制其行为. 比如, 如果你指定--logtostderr on, 你可以在命令中这样调用你的程序:

./your_application --logtostderr=1

如果Google gflags library 没有安装, 则你需要设置环境变量, 在参数前加 “GLOG_”, e.g.

GLOG_logtostderr=1 ./your_application

下列参数是经常用到的:

logtostderr (bool, default=false)
记录消息到stderr而不是log文件
注意: 你可以用1,true,yes来指代(不分大小写). 同样, 你也能用0,false,no来指代(不分大小写).

stderrthreshold (int, default=2, which is ERROR)
除了log文件还复制指定级别和这个级别之上的消息到. 这些严重性等级INFO, WARNING, ERROR, 和 FATAL 对应的数字分别是 0, 1, 2, 和 3,.

minloglevel
(int, default=0, which is INFO)
记录指定的等级和之上的等级,再次的,这些严重性等级INFO, WARNING, ERROR, 和 FATAL 对应的数字分别是 0, 1, 2, 和 3,.

log_dir (string, default=””)
把日志写入到指定的目录中


v
(int, default=0)
显示所有VLOG(m)的值,前提是m小于或等于指定的参数值.指定这个参数会覆盖–vmodule. 看the section about verbose logging 以了解更多的信息.

vmodule (string, default=””)
Per-module verbose level. The argument has to contain a comma-separated list of <module name>=<log level>. <module name> is a glob pattern (e.g., gfs* for all modules whose name starts with “gfs”), matched against the filename base (that is, name ignoring .cc/.h./-inl.h). <log level> overrides any value given by –v. See also the section about verbose logging.

在logging.cc还有一些其他的参数. 可以搜索”DEFINE_” 去看完整的参数信息.

条件/临时日志

有时,你可能需要在某些指定条件发生的时候记录一条消息. 你可以这样做:

LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";


“Got lots of cookies” 消息只有当变量num_cookies 大于10的时候才会被记录. 那么它很合适用来在一个循环中只记录一条日志. 这种类型的日志常常用来作为提示信息.

LOG_EVERY_N(INFO, 10) << "Got the " << COUNTER << "th cookie";

上述代码将每隔10次输出一次. 注意指定的COUNTER变量被用来指定重复的变量.

你也能用下面的方式联合条件日志和临时日志 宏来使用。

LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << COUNTER
<< "th big cookie";

作为替代没N次输出一条日志,你也能限定首次发生的次数:

LOG_FIRST_N(INFO, 20) << "Got the " << COUNTER << "th cookie";

在循环20次之后就会输出日志信息. 再一次的,COUNTER指定了循环变量.

Debug模式支持

指定”debug mode”宏将只在debug模式下记录log信息,在非debug模式下将不记录日志信息. 使用这个宏是为了避免因为记录过多日志而拖慢程序性能.

DLOG(INFO) << "Found cookies";
DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
DLOG_EVERY_N(INFO, 10) << "Got the " << COUNTER << "th cookie";

CHECK 宏

这是一个非常好的习惯,它使你尽早的发现尽可能多的错误成为可能. CHECK宏提供了一种能力:当预先定义的条件不满足时停止程序, 与保准C库中的assert宏类似.

如果指定的表达式不是true,则CHECK会终止程序. 与assert不同的是, 它并不被NDEBUG所控制(也就是并不只是在debug摸下下游泳), 因此check并不管编译的模式. 因此, fp->Write(x) 在下面的例子中总是会被执行:

   CHECK(fp->Write(x) == 4) << "Write failed!";

还有各种各样的 相等/不相等 的checks:CHECK_EQ, CHECK_NE, CHECK_LE, CHECK_LT, CHECK_GE, 和CHECK_GT. 他们比较两个值,如果定义的条件表达式不成立,则记录一个FATAL消息. The values must have operator<<(ostream, ...) defined.

你可以像这样增加一个错误信息:

   CHECK_NE(1, 2) << ": The world must be ending!";

我们非常小心的去确保每个参数只计算一次, and that anything which is legal to pass as a function argument is legal here. In particular, the arguments may be temporary expressions which will end up being destroyed at the end of the apparent statement, for example(没看明白):

   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++ stream那样。在程序崩溃前,请使用上文描述的 CHECK_EQ 去记录一个自定义的日志信息.

如果你要比较两个C风格的字符串(char *), 一些方便的宏可以做区分大小写和不区分大小写的比较- CHECK_STREQ, CHECK_STRNE, CHECK_STRCASEEQ, and CHECK_STRCASENE. CASE版本是不区分大小写的. 你可以安全的传递NULL指针。NULL和非NULL字符串比较的结果是不相等,两个NULL比较的结果是相等.

要注意的是两个参数有可能是临时字符串,这意味着在当前作用域后会被销毁。(e.g., CHECK_STREQ(Foo().c_str(), Bar().c_str()) where Foo and Bar return C++’s std::string).

CHECK_DOUBLE_EQ宏检查两个浮点数的相等性,接受一个小误差. CHECK_NEAR accepts a third floating point argument, which specifies the acceptable error margin.

Verbose Logging

When you are chasing difficult bugs, thorough log messages are very useful. However, you may want to ignore too verbose messages in usual development. For such verbose logging, glog provides the VLOG macro, which allows you to define your own numeric logging levels. The --v command line option controls which verbose messages are logged:

   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";

With VLOG, the lower the verbose level, the more likely messages are to be logged. For example, if --v==1, VLOG(1) will log, but VLOG(2) will not log. This is opposite of the severity level, where INFO is 0, and ERROR is 2. --minloglevel of 1 will log WARNING and above. Though you can specify any integers for both VLOG macro and --v flag, the common values for them are small positive integers. For example, if you write VLOG(0), you should specify --v=-1 or lower to silence it. This is less useful since we may not want verbose logs by default in most cases. The VLOG macros always log at the INFO log level (when they log at all).

Verbose logging can be controlled from the command line on a per-module basis:

   --vmodule=mapreduce=2,file=1,gfs*=3 --v=0

will:

  • a. Print VLOG(2) and lower messages from mapreduce.{h,cc}
  • b. Print VLOG(1) and lower messages from file.{h,cc}
  • c. Print VLOG(3) and lower messages from files prefixed with “gfs”
  • d. Print VLOG(0) and lower messages from elsewhere

The wildcarding functionality shown by (c) supports both ‘*’ (matches 0 or more characters) and ‘?’ (matches any single character) wildcards. Please also check the section about command line flags.

There’s also VLOG_IS_ON(n) “verbose level” condition macro. This macro returns true when the --v is equal or greater than n. To be used as

   if (VLOG_IS_ON(2)) {
     // do some logging preparation and logging
     // that can't be accomplished with just VLOG(2) << ...;
   }

Verbose level condition macros VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N behave analogous to LOG_IF, LOG_EVERY_N, LOF_IF_EVERY, but accept a numeric verbosity level as opposed to a severity level.

   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 " << 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 " << COUNTER;

Failure Signal Handler

The library provides a convenient signal handler that will dump useful information when the program crashes on certain signals such as SIGSEGV. The signal handler can be installed by google::InstallFailureSignalHandler(). The following is an example of output from the signal handler.

*** 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)

By default, the signal handler writes the failure dump to the standard error. You can customize the destination by InstallFailureWriter().

Miscellaneous Notes

Performance of Messages

The conditional logging macros provided by glog (e.g., CHECK, LOG_IF, VLOG, …) are carefully implemented and don’t execute the right hand side expressions when the conditions are false. So, the following check may not sacrifice the performance of your application.

   CHECK(obj.ok) << obj.CreatePrettyFormattedStringButVerySlow();
User-defined Failure Function

FATAL severity level messages or unsatisfied CHECK condition terminate your program. You can change the behavior of the termination by InstallFailureFunction.

   void YourFailureFunction() {
     // Reports something...
     exit(1);
   }

   int main(int argc, char* argv[]) {
     google::InstallFailureFunction(&YourFailureFunction);
   }

By default, glog tries to dump stacktrace and makes the program exit with status 1. The stacktrace is produced only when you run the program on an architecture for which glog supports stack tracing (as of September 2008, glog supports stack tracing for x86 and x86_64).

Raw Logging

The header file <glog/raw_logging.h> can be used for thread-safe logging, which does not allocate any memory or acquire any locks. Therefore, the macros defined in this header file can be used by low-level memory allocation and synchronization code. Please check src/glog/raw_logging.h.in for detail.

Google Style perror()

PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and CHECK equivalents with the addition that they append a description of the current state of errno to their output lines. E.g.

   PCHECK(write(1, NULL, 2) >= 0) << "Write NULL failed";

This check fails with the following error message.

   F0825 185142 test.cc:22] Check failed: write(1, NULL, 2) >= 0 Write NULL failed: Bad address [14]
Syslog

SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available. These log to syslog in addition to the normal logs. Be aware that logging to syslog can drastically impact performance, especially if syslog is configured for remote logging! Make sure you understand the implications of outputting to syslog before you use these macros. In general, it’s wise to use these macros sparingly.

Strip Logging Messages

Strings used in log messages can increase the size of your binary and present a privacy concern. You can therefore instruct glog to remove all strings which fall below a certain severity level by using the GOOGLE_STRIP_LOG macro:

If your application has code like this:

   #define GOOGLE_STRIP_LOG 1    // this must go before the #include!
   #include <glog/logging.h>

The compiler will remove the log messages whose severities are less than the specified integer value. Since VLOG logs at the severity level INFO (numeric value 0), setting GOOGLE_STRIP_LOG to 1 or greater removes all log messages associated with VLOGs as well as INFO log statements.

Notes for Windows users

Google glog defines a severity level ERROR, which is also defined in windows.h There are two known workarounds to avoid this conflict:

  • #define WIN32_LEAN_AND_MEAN or NOGDI before you #include windows.h .
  • #undef ERROR after you #include windows.h .

原文地址:http://google-glog.googlecode.com/svn/trunk/doc/glog.html

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注