关闭

如何使用Google日志库 (glog)

标签: glist
9333人阅读 评论(0) 收藏 举报
分类:
如何使用Google日志库 (glog)

介绍

Google glog是一个应用层的库. 它提供基于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";
   }

Google glog定义了一系列的宏处理普通的日志工作. 你可以分级记录, control loggingbehavior from the command line, 按条件记录, abort theprogram when expected conditions are not met, introduce your ownverbose logging levels, 及其它. 文本只是简单的介绍了常用的glog功能而不是所有的细节.没介绍到的,自己读代码去吧.


严重等级

严重等级包括(按严重程度排序): INFO, WARNING,ERROR,和FATAL.记录一个FATAL级的错误后会自动终止程序执行(其实就是_asm int 3).一个严重等级高的记录不但记录在它自己的文件,也记录在比它低等的文件里.例如, 一个FATAL级的记录将会记在FATAL, ERROR,WARNING, 和INFO等级的日志里.

在debug状态下FATAL级记录也可以用DFATAL(当没定义NDEBUG宏的时候),发给客户的程序最好不要用FATAL小心客户对你使用_asm int 3,这时ERROR是个不错的选择.

glog默认把日志文件命名为"/tmp/...log...."(例如, "/tmp/hello_world.example.com.hamaji.log.INFO.20080709-222411.10474").glog默认把ERRORFATAL 级的记录发送一份到stderr.


设置标志

标志可以改变glog的输出行为.如果你安装了Googlegflags library, configure 脚本 (具体请参考它的INSTALL文件)会自动检测并使用标志,这时你可以通过命令行使用标志.例如, 若你想发送 --logtostderr 标志,像下面这样:

   ./your_application --logtostderr=1
如果你没装Google gflags library,你就只能用带GLOG_的环境变量实现,例如.
   GLOG_logtostderr=1 ./your_application    (貌似在Windows里不能这样用吧?)

常用的标志有:

logtostderr (bool, default=false)
写日志到stderr而不是日志文件.
Note: you can set binary flags to true by specifying1, true, or yes (caseinsensitive).Also, you can set binary flags to false by specifying0, false, or no (again, caseinsensitive).

stderrthreshold (int, default=2, whichis ERROR)
将某级及以上级别的记录同时发送到stderr和日志文件. 严重等级INFO, WARNING, ERROR, FATAL 分别对应 0, 1, 2, 3.

minloglevel (int, default=0, whichis INFO)
只记录某级及以上级别的记录.

log_dir (string, default="")
指定日志保存的目录.

v (int, default=0)
Show all VLOG(m) messages for m less orequal the value of this flag. Overridable by --vmodule.See the section about verbose logging for moredetail.

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

还有一些其它的标志,自己去logging.cc里面搜索"DEFINE_",爷就不多说了.


你也可以在程序里修改FLAGS_* 开头的全局变量. 通常设置FLAGS_*开头的变量会立即生效,和日志文件名或路径相关的变量例外.例如FLAGS_log_dir就不能放在google::InitGoogleLogging后面.例子代码:

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

条件/ Occasional Logging

下面的宏用于根据条件写日志:

   LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
只有当num_cookies > 10的时候才会记录"Got lots of cookies"
如果有的代码执行非常频繁,你肯定不会希望每次都写入日志.这时,你可以使用下面的方法:
   LOG_EVERY_N(INFO, 10) <  Got the   googleCOUNTER  th cookiepre>

上面的代码只有当第1次,第11次,第21次....执行时才写入日志.Note that the specialgoogle::COUNTER value is used to identify which repetition ishappening.

条件和计次可以混合使用,例如:

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

除了间隔N次输出,还可以只输出前M次,例如:

   LOG_FIRST_N(INFO, 20) <  Got the   googleCOUNTER  th cookiepre>

只输出前20次.

Debug mode支持

"debug mode"的宏只在调试模式有效,其他模式不生效.上栗子:

   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宏就是干这个滴,它的功能和assert一样,条件不符合时终止程序.

assert不同的是它*不*NDEBUG的限制,无论是不是debug编译它都执行.所以下面的fp-<Write(x)会被执行:

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

有各种各样的宏用于CHECK相等/不相等,包括: CHECK_EQ,CHECK_NE, CHECK_LE, CHECK_LT,CHECK_GE,和CHECK_GT.它们会记录一个FATAL级的记录到日志,牛X的是他们还会把对比的两个值也一起记录.(那两个值必须定义了 operator< ostreamcode> ).例如:

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

We are very careful to ensure that each argument is evaluated exactlyonce, and that anything which is legal to pass as a function argument islegal here. In particular, the arguments may be temporary expressionswhich will end up being destroyed at the end of the apparent statement,for example:

   CHECK_EQ(string("abc")[1], 'b');

The compiler reports an error if one of the arguments is apointer and the other is NULL. To work around this, simply static_castNULL to the type of the desired pointer.

   CHECK_EQ(some_ptr, static_cast(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字符串(char *)可以用:CHECK_STREQ, CHECK_STRNE,CHECK_STRCASEEQ,和CHECK_STRCASENE.带CASE的区分大小写. 这个宏参数可以用NULL指针.NULL与non-NULL比不等.两个NULL是相等的.

Note that both arguments may be temporary strings which aredestructed at the end of the current "full expression"(e.g., CHECK_STREQ(Foo().c_str(), Bar().c_str()) whereFoo and Bar return C++'sstd::string).

CHECK_DOUBLE_EQ 用于对比浮点数,会有小小的误差.CHECK_NEAR 可以接受一个浮点数作为误差.

详细日志

VLOG宏,你还可以定义自己的严重等级. The --v command line option controlswhich 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 morelikely messages are to be logged. For example, if--v==1, VLOG(1) will log, butVLOG(2) will not log. This is opposite of the severitylevel, where INFO is 0, and ERROR is 2.--minloglevel of 1 will log WARNING andabove. Though you can specify any integers for both VLOGmacro and --v flag, the common values for them are smallpositive integers. For example, if you write VLOG(0),you should specify --v=-1 or lower to silence it. Thisis less useful since we may not want verbose logs by default in mostcases. The VLOG macros always log at theINFO log level (when they log at all).

Verbose logging can be controlled from the command line on aper-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" conditionmacro. This macro returns true when the --v is equal orgreater 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 behaveanalogous to LOG_IF, LOG_EVERY_N,LOF_IF_EVERY, but accept a numeric verbosity level asopposed 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 " << 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;

Failure Signal Handler

The library provides a convenient signal handler that will dump usefulinformation when the program crashes on certain signals such as SIGSEGV.The signal handler can be installed bygoogle::InstallFailureSignalHandler(). The following is an example of outputfrom 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 standarderror. 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, ...) arecarefully implemented and don't execute the right hand sideexpressions when the conditions are false. So, the following checkmay not sacrifice the performance of your application.

   CHECK(obj.ok) << obj.CreatePrettyFormattedStringButVerySlow();

User-defined Failure Function

FATAL severity level messages or unsatisfiedCHECK condition terminate your program. You can changethe behavior of the termination byInstallFailureFunction.

   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 programexit with status 1. The stacktrace is produced only when you run theprogram on an architecture for which glog supports stack tracing (asof September 2008, glog supports stack tracing for x86 and x86_64).

Raw Logging

The header file can beused for thread-safe logging, which does not allocate any memory oracquire any locks. Therefore, the macros defined in thisheader file can be used by low-level memory allocation andsynchronization code.Please check src/glog/raw_logging.h.in for detail.

Google Style perror()

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

   PCHECK(write(1, NULL, 2) <= 0) <  Write NULL failedpre>

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, andSYSLOG_EVERY_N macros are available.These log to syslog in addition to the normal logs. Be aware thatlogging to syslog can drastically impact performance, especially ifsyslog is configured for remote logging! Make sure you understand theimplications of outputting to syslog before you use these macros. Ingeneral, it's wise to use these macros sparingly.

Strip Logging Messages

Strings used in log messages can increase the size of your binaryand present a privacy concern. You can therefore instruct glog toremove all strings which fall below a certain severity level by usingthe 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 lessthan the specified integer value. SinceVLOG logs at the severity level INFO(numeric value 0),setting GOOGLE_STRIP_LOG to 1 or greater removesall log messages associated with VLOGs as well asINFO log statements.

对于Windows用户

glog的ERROR级错误与windows.h冲突. You can make glog not defineINFO, WARNING, ERROR,and FATAL by definingGLOG_NO_ABBREVIATED_SEVERITIES beforeincluding glog/logging.h . Even with this macro, you canstill use the iostream like logging facilities:

  #define GLOG_NO_ABBREVIATED_SEVERITIES
  #include <windows.h>
  #include <glog/logging.h>

  // ...

  LOG(ERROR) << "This should work";
  LOG_IF(ERROR, x > y) << "This should be also OK";

However, you cannotuse INFO, WARNING, ERROR,and FATAL anymore for functions definedin glog/logging.h .

  #define GLOG_NO_ABBREVIATED_SEVERITIES
  #include <windows.h>
  #include <glog/logging.h>

  // ...

  // This won't work.
  // google::FlushLogFiles(google::ERROR);

  // Use this instead.
  google::FlushLogFiles(google::GLOG_ERROR);

If you don't need ERROR definedby windows.h, there are a couple of more workaroundswhich sometimes don't work:

  • #define WIN32_LEAN_AND_MEAN or NOGDIbefore you #include windows.h .
  • #undef ERRORafter you #include windows.h .

See this issue for more detail.

Shinichiro Hamaji
Gregor Hohpe
Fri Jan 25 2013

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:130243次
    • 积分:1712
    • 等级:
    • 排名:千里之外
    • 原创:44篇
    • 转载:2篇
    • 译文:2篇
    • 评论:15条
    最新评论