欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

glog简介

程序员文章站 2022-03-20 14:06:10
...

引言

原文英文链接.翻译中有一些个人添加的辅助信息,以括号标识,”注:”开头,以粗体表示,例如(注:以下为个人翻译,水平有限,欢迎指正).
Google glog是一个应用级别的日志系统库.它提供基于C++风格的流和各种辅助宏的日志API.你可以使用LOG(<特定等级>)输出日志信息信息,例如:

#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定义了一系列的宏简化的常用的日志任务.你可以输出不同严重等级的日志信息,通过命令行控制日志的行为,基于特定条件的日志输出,当期望的条件没有触发时中止程序运行,引入你自己的更多的日志等级等等.这个文档介绍glog所支持的功能.这个文档并不能描述glog库的所有功能,仅是最有用的部分.如果你希望看到一些不常用的功能,请查阅src/glog文件夹里的头文件.
- google-glog
- Github:glog

严重性等级

你可以指定以下严重性等级中的一个(严重性从低到高):INFO,WARNING,ERROR,FATAL.输出一个FATAL信息会中止程序(在这条信息输出之后中止).注意:一个特定严重等级的日志信息不仅仅输出到该严重等级的日志文件中,它还会被记录到比它严重等级更低的文件中.例如,一个严重等级为FATAL的日志信息将会被记录到严重等级为FATAL,ERROR,WARNING,INFO的所有文件中.
DFATAL在debug模式下是一个FATAL等级的日志输出(例如,没有NDEBUG宏定义),为了避免软件在发布后被停止运行,严重等级会自动的被降低到 ERROR.
除非另有指定,glog默认将日志写入:

/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的日志信息除了输出到日志文件中,还会输出到标准错误中(stderr).

设置标志

一些标志影响glog的输出行为.如果Google gflags library已经安装到你的电脑上,configure脚本(查看在包中的INSTALL文件,有详细的脚本)将自动的检测并使用它,同时允许通过命令行传递标志.例如,如果你希望打开–logtostderr标志,你可以使用下面的命令行启动应用程序:

   ./your_application --logtostderr=1

如果你并未安装Google flags library,你可以通过环境变量设置标志,以’GLOG_’作为标志名的前缀,例如:

   GLOG_logtostderr=1 ./your_application

以下是常用的标志:
logtostderr (bool,default=false)
日志信息将不会输出到日志文件中,而是输出到stderr.
注:你可以通过指定为1,true,yes(大小写敏感),设置标志为true. 你可以指定为0,false,no(大小写敏感)设置标志为false.
stderrthreshold(int, default=2, which is ERROR)
将大于严重等级阀值日志信息除了输出到日志文件中,还会输出到stderr中.严重等级INFO,WARNING,ERROR,FATAL分别对应0,1,2,3.
minloglevel (int, default=0, which is INFO)
大于或等于这个等级的日志将会被打印出来.
log_dir (string, default=”“)
设置日志指定的日志文件夹.
v (int, default=0)
显示所有VLOG(m)小于或等于这个标志’m’的信息.可以用–vmodule代替.详细见verbose logging.
vmodule (string, default=”“)
每个模块的verbose等级.这个参数会在有系列逗号分别的列表中,=.是全局(例如gfs*表示gfs开头的所有模块).可以通过’–v’.详细见the section about verbose logging.
还有许多其他的标志定义在logging.cc中.请使用grep(linux里的grep命令,windows上就自己搜索下)搜索源码查看所有的标志,这些标志位定义以’DEFINE_’开头.
你还可以通过在程序中修改全局变量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";

条件型/特殊情况型日志

有时,你只希望在特定的情况下输出日志.你可以使用一下的宏来执行条件日志:

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

“Got lots of cookies”信息只有在变量num_cookies大于10时才会被打印.如果一段代码被多次执行,按照一定的间隔来输出日志信息是有用的(否则每次都执行,log量很大不便分析),可以按如下方式打印:

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

上面的代码会在第一次,第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次后,这个打印会被输出.google::COUNTER标识已经重复的次数.

支持调试模式

“调试模式”日志宏只在调试模式下才生效,非调试模式下不起作用.可以使用这些宏来避免执行不必要的日志从而拖慢你的应用.

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

CHECK宏

在你的程序中经常检测预期的条件者是一个很好的做法,它能够尽早的发现错误.CHECK宏提供了这种功能,当条件不满足时将会中止应用程序,这类似于标准C库里定义的assert宏.
如果条件不满足CHECK中止应用程序,它不受控于NDEBUG,CHECK将无视编译模式(不论是调试模式,还是正常模式,CHECK都会起作用),因此,fp->Write(x)永远都会被执行:

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

有许多帮助宏来表示相等或不等的情况-CHECK_EQ,CHECK_NE,CHECK_LE,CHECK_LT,CHECK_GE以及CHECK_GT.他们比较2个值的情况,当结果不是所期望的情况下会输出FATAL日志信息,这个信息包含这2个值,这些值必须定义operator<<(ostream,…).
你可能添加错误信息如下:

CHECK_NE(1,2) << ": The wrold 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++流.
如果你比较C字符串(char ),有一套宏来执行比较,这套宏可以区分/不区分大小写-*CHECK_STREQ,CHECK_STRNE,CHECK_STRCASEEQ,CHECK_STRCASENE.CASE版本是不区分大小写的.这几个宏使用中你可以安全的传递NULL指针.NULL指针是非NULL指针总是不相等的.两个NULL指针是相等的.
注意2个参数可能是临时字符串,它们在表达式之后就会被销毁.
CHECK_DOUBLE_EQ宏检测两个浮点数的值是否相等,误差很小(0.000000000000001L).CHECK_NEAR可以设置误差的大小(CHECK_DOUBLE_EQ的扩展版本,看一下源码定义就知道了).

Verbose日志

当你在处理困难的bug时,详尽的日志信息是非常有帮助的.但是你希望忽略一些冗长的信息.为了这样的verbose日志,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中,verbose等级越低,越有可能被打印出来.例如,如果–v=1,VLOG(1)将会输出日志,VLOG(2)不会输出日志.这个与之前的严重等级相反,严重等级中INFO是0,ERROR是2.–minloglevel如果是1,那么WARNING以及以上的严重等级会被输出.虽然你可以为VLOG和–v标志指定任何的整数,但通常指定为比较小的正整数.例如,如果你代码写了VLOG(0),你应该指定–v=-1或更小的值才能使它不被打印.在多数情况下我们不会这么设置verbose日志.VLOG宏总是以INFO等级的log输出.
Verbose日志通过命令行来指定每个模块的日志控制情况:

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

表示:

  • a. 在mapreduce中打印VLOG(2) 和更低等级的信息.
  • b. 在file中打印VLOG(1)和等级更低的信息.
  • c. 在以’gfs’为前缀的文件中打印VLOG(3)和等级更低的信息.
  • d. 在其他地方打印VLOG(0)和等级更低的信息.
    命令行中支持通配符’*’(表示0个或多个单词)以及’?’(匹配任何一个单词).详细见command line flags.
    还有”verbose”等级控制宏VLOG_IS_ON(n).当–v和n相等或比n更大时,宏返回true,如下所示:
if(VLOG_IS_ON(2)){
    //do some logging preparation and logging
    //that can't accomplished with just LOG(2) << ...;
}

Verbose等级条件宏VLOG_IF,VLOG_EVERY_N,VLOG_IF_EVERY_N,行为类似于LOG_IF,LOG_EVERY_N,LOG_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时可以导出非常有用的信息.信号处理可以调用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提供的条件型日志宏(例如:CHECK,LOG_IF,VLOG,…)被小心的实现着以便当条件不满足时,右边的表达式不会被执行.所以如下的CHECK不会影响你的应用的性能(obj.ok为false,后面不会被执行):

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

用户自定义的异常函数

严重等级为FATAL的信息或是不满足CHECK的条件,你的程序将会被中止.你可以通过使用InstallFailureFunction来代替中止的行为.

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

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

默认情况下,glog尽力导出堆栈信息,并且让应用程序返回状态1.堆栈追踪信息只在已经支持的平台上实现(2008年9月,glog支持x86和x86_64).

原日志

头文件

Google风格的perror()

PLOG(),PLOG_IF()PCHECK()的作用与LOG,CHECK,相似,它附带了errorno的信息.例如:

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

如果上面的PCHECK的表达式为表达式为false,那么会有如下的错误信息:

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

SYSLOG

SYSLOG,SYSLOG_IF,SYSLOG_EVERY_N宏都是有效的.这些日志除了正常的日志外,还会写入系统日志中.注意记录到syslog可能会影响性能,特别是当它配置为远程日志时!确保你在使用系统日志时候,你对它们是非常了解的.通常情况下,尽量少用这些是明智的.

精简日志信息

日志中包含大量的字符串会增加二进制文件的大小,同时会暴露隐私问题.你可以使用GOOGLE_STRIP_LOG宏来移除哪些严重等级小于特定等级的日志:
如果你的应用程序代码如下:

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

编译器将会移除严重程度低于指定级别的日志.因为VLOG日志处于严重等级的INFO等级(即0),设置GOOGLE_STRIP_LOG为1或更大的值,将移除与VLOG相关的日志信息,当然也包括INFO指定的日志信息.

windows用户注意事项

Google glog定义了ERROR的严重等级,它也被定义在windows.h中.你可以在glog/logging.h之前定义GLOG_NO_ABBREVIATED_SEVERITIES来使glog不对INFO,WARNING,ERROR,FATAL定义,定义了这个宏之后,你仍然可以使用iostream日志工具:

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

但是,你不能使用INFO,WARNING,ERROR,FATAL这些已经在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);

如果你 不想用windows.h中定义的ERROR:

  • 在”#include < windows.h >”之前”#define WIN32_LEAN_AND_MEAN”或”#define NOGDI”.
  • 在”#include < windows.h >”之后”#undef ERROR”.
相关标签: glog