How To Use Google Logging Library
Glog 的基本使用方法在google code上有介绍:How To Use Google Logging Library ;最好有VPN,不然访问的时候估计又是加载不了,吐槽下GFW;
以下对 上述文档的翻译大部分来自 :Glog 使用帮助 ,这位哥们写的也是转的,但是没出处,所以原文在出自哪里我也不清楚,感谢不知名人士。少部分来自我自己的补充,有不对之处希望指出;
1. 概述
Google glog是一个基于程序级记录日志信息的c++库,编程使用方式与c++的stream操作类似,例:
LOG(INFO) << "Found " << num_cookies << " cookies";
“LOG”宏为日志输出关键字,“INFO”为严重性程度。
主要支持功能:
1, 参数设置,以命令行参数的方式设置标志参数来控制日志记录行为;
2, 严重性分级,根据日志严重性分级记录日志;
3, 可有条件地记录日志信息;
4, 条件中止程序。丰富的条件判定宏,可预设程序终止条件;
5, 异常信号处理。程序异常情况,可自定义异常处理过程;
6, 支持debug功能。可只用于debug模式;
7, 自定义日志信息;
8, 线程安全日志记录方式;
9, 系统级日志记录;
10, google perror风格日志信息;
11, 精简日志字符串信息。
2. 功能使用
1.1 参数设置
可通过命令行方式设置glog的标志参数,用来控制日志记录行为。
命令格式如下:
标志名1 = 标志值 标志名2=标志值 …… 标志值n=标志值 ./程序名
所有标志名需添加统一前缀—“GLOG_”,不同标志语句之间以空格相隔;
例如:
-- GLOG_vmodule=mapreduce=2,file=1,gfs*=3 -- GLOG_v=0 ./application.exe
常用标志参数类型及其作用说明:
标志参数 |
类型 |
作用 |
logtostderr |
bool |
值为true的时候,日志信息输出到stderr,并非文件。默认值为 false。 |
stderrthreshold |
int |
严重性级别在该门限值以上的日志信息除了写入日志文件以外,还要输出到stderr。各严重性级别对应的数值:INFO—0,WARNING—1,ERROR—2,FATAL—3 默认值为2. |
minloglevel |
int |
严重性级别在该门限值以上的日志信息才进行记录。 默认值为0. |
log_dir |
string |
日志信息记录路径。默认为空,如果没有指定信息输出到stderr,则信息保存在"/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"). |
v |
int |
对于使用“ VLOG(m)”(m为int型)表达式进行输出的日志信息,只在m的值小于该标志的值的时候,才进行输出。另外, 该设置可能被 vmodule标志给覆盖.默认为0. |
vmodule |
string |
分模块(文件)设置VLOG(m)日志信息的输出基本。命令格式为以逗号分开的“<module name>=<log level>”表达式组成。其中<module name> 是“glob pattern”,支持通配符,<module name>不包括文件的扩展名(.h,.cc等)。 |
表1标志说明
还有其他的标志参数定义在logging.cc,可在文件中搜索“DEFINE_”来进行查看。
1.2 严重性分级记录信息
glog可通过根据指定的严重性等级,来选择性记录日志。日志信息严重性等级按由低到高排列依次为:INFO,WARNING, ERROR, 和 FATAL四级。使用者可以在命令行中设置严重性等级门限值来控制日志的输出,详细见“参数设置”部分的“minloglevel”标志值的介绍。
1.3 有条件地记录日志信息
glog可以控制日志信息在指定条件下进行记录。具体使用如下:
1, LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
上面的语句表示,只有当num_cookies > 10条件成立时,“Got lots of cookies”日志信息才被记录。
2, LOG_EVERY_N(INFO, 10) << "Got the " << COUNTER << "th cookie";
上面的语句表示,在程序中周期性的记录日志信息,在该语句第1、11、21……次被执行的时候,记录日志信息。COUNTER变量表示该语句被执行的次数。
3, LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << COUNTER<<
"th big cookie";
上面的语句为1,2项功能的合并,size>1024的条件连续成立10次的时候记录日志信息。COUNTER变量表示该条件成立的次数。
4, LOG_FIRST_N(INFO, 20) << "Got the " << COUNTER << "th cookie";
上面的语句表示,当该语句只在首次执行了20次以后记录日志信息, COUNTER变量表示该语句被执行的次数。
1.4 有条件地中止程序
glog提供了CHECK宏,用于在调试地时候中止程序,及早发现程序错误。当通过该宏指定的条件不成立的时候,程序会中止,并且记录对应的日志信息。功能类似于ASSERT,区别是CHECK宏不受NDEBUG约束,在release版中同样有效。具体使用如下:
CHECK(fp->Write(x) == 4) << "Write failed!";
当fp->Write(x) == 4成立时,记录“Write failed!”日志信息,并且中止程序,其中fp->Write(x) == 4为判定条件,日志信息以c++的stream操作形式生成。
glog提供了多个便利的宏来处理特定关系的判定。具体有:
1,判定大小关系
CHECK_EQ, CHECK_NE, CHECK_LE, CHECK_LT, CHECK_GE, CHECK_GT,使用这些宏需要注意类型一致,如果出现类型不一致的,可使用static_cast转换。
2,判定指针是否为空
CHECK_NOTNULL(some_ptr),可用于对象初始化的时候。
3,判定字符串是否相等
CHECK_STREQ, CHECK_STRNE, CHECK_STRCASEEQ, CHECK_STRCASENE。可进行大小写敏感或不敏感字符串来分别判定。
4, 判定浮点是否相等或相近
CHECK_DOUBLE_EQ,CHECK_NEAR。这两个宏都需要指定一个可容忍的偏差上限。
当这些宏判定条件不成立时,glog会生成一个FATAL级别的日志信息,该信息包含比较的两个值和stream方式传入的字符串,然后中止程序。
1.5 异常信号处理
glog提供了比较方便的程序异常处理机制。例如,当程序出现SIGSEGV异常信号时,glog的默认异常处理过程会导出非常有用的异常信息。异常处理过程可以通过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)
默认情况下,异常信息是输出到stderr,通过InstallFailureWriter()可以改变输出目标。
1.6 支持debug功能
glog提供特定的宏只在debug模式下生效。以下分别对应LOG、LOG_IF、DLOG_EVERY_N操作的专用宏。
DLOG(INFO) << "Found cookies";
DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
DLOG_EVERY_N(INFO, 10) << "Got the " << COUNTER << "th cookie";
1.7 自定义日志信息
glog提供VLOG宏,让用户自定义分级信息,该分级与LOG宏对应的严重性分级是独立管理,在命令行参数设置中独立设置“v”或“vmodule”参数来控制,具体见“参数设置”部分标志说明。VLOG宏便于用户调试、查找完问题以后,屏蔽日志信息,减轻负担。具体使用如下:
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";
上面的语句,只有在size>1024成立时且命令行参数v的值不小于1,才记录日志信息。
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;
上面的语句,只有在命令行参数v的值不小于1时,才会每执行10次记录一次日志信息。
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;
上面的语句,只有在命令行参数v的值不小于1时,若size>1024条件连续成立10次,记录一次日志信息。
1.8 线程安全日志记录
glog提供了线程安全的日志记录方式。在<glog/raw_logging.h>文件中提供了相关的宏,如,RAW_CHECK,RAW_LOG等。这些宏的功能与CHECK,LOG等一致,除此以外支持线程安全,不需要为其分配任何内存和提供额外的锁(lock)机制。
1.9 系统级日志记录
glog除了提供了普通的日志记录宏,还提供SYSLOG, SYSLOG_IF,和 SYSLOG_EVERY_N宏,这些宏将日志信息通过syslog()函数记录到系统日志。这个貌似只支持linux,windows 编译的时候无法通过,报的错的是找不到 syslog()函数,而且使用到的syslog.h也找不到;
1.10 google perror风格日志信息
glog提供了与LOG*和CHECK宏作用等价的PLOG()、PLOG_IF() 和PCHECK()宏,不同的是,后者在记录日志信息的时候,会将errno的状态及其描述附加到日志描述中。
如:
PCHECK(write(1, NULL, 2) >= 0) << "Write NULL failed";
当条件不成立时,会输出日志信息:
F0825 185142 test.cc:22] Check failed: write(1, NULL, 2) >= 0 Write NULL failed: Bad address [14]
1.11 精简日志字符串信息
日志信息的字符串会占用比较大的内存空间,另外还带来隐私泄露的问题。glog提供了GOOGLE_STRIP_LOG宏在编译时候去除日志的字符串信息。
3. 其他说明
1, windows平台使用注意
因为glog的严重性级别中使用了ERROR宏,与<windows.h>文件中冲突,可通过以下两种方式避免:
a,在包含<windows.h>文件之前,定义宏WIN32_LEAN_AND_MEAN 或者NOGDI。
b,在包含<windows.h>文件之后,undef掉ERROR定义。
2,FLAGS_V 编译的时候报错error LNK2001: unresolved external symbol
需要包含这两个头文件
#include "config_for_unittests.h"
#include "utilities.h"
4.基本代码
using namespace GOOGLE_NAMESPACE; //必须包含
int main(int argc,char *argv[])
{
google::InitGoogleLogging(argv[0]); //初始化log,参数argv[0]就是程序名
// 像下面对INFO、ERROR、WARNING 三个级别的错误日志都指明了存放位置,如果是同一个位置的话三个文件会合在一起成为一个文件;假设我们只指定INFO文件位置的话,在指定位置的日志里我们可以看到文件中包含的日志也有ERROR、WARNING,但是在windows TEMP 目录下也会生成两个文件,一个是WARING,一个是ERROR;
google::SetLogDestination(google::INFO,installPath.c_str()); //INFO级别的日志都存放到installPath目录下
google::SetLogDestination(google::ERROR,installPath.c_str());//ERROR级别的日志都存放到installPath目录下
google::SetLogDestination(google::WARNING,installPath.c_str());//WARNING级别的日志都存放到installPath目录下
google::SetStderrLogging(google::INFO); //输出到标准输出的时候大于INFO级别的都输出;
FLAGS_logbufsecs = 0; //日志实时输出
FLAGS_max_log_size = 1024; // max log size is 1024M
return 0;
}
初始化日志模块的时候设置一些以下的参数在头文件src/glog/logging.h中
// Set whether log messages go to stderr instead of logfiles
DECLARE_bool(logtostderr);
// Set whether log messages go to stderr in addition to logfiles.
DECLARE_bool(alsologtostderr);
// Set color messages logged to stderr (if supported by terminal).
DECLARE_bool(colorlogtostderr);
// Log messages at a level >= this flag are automatically sent to
// stderr in addition to log files.
DECLARE_int32(stderrthreshold);
// Set whether the log prefix should be prepended to each line of output.
DECLARE_bool(log_prefix);
// Log messages at a level <= this flag are buffered.
// Log messages at a higher level are flushed immediately.
DECLARE_int32(logbuflevel);
// Sets the maximum number of seconds which logs may be buffered for.
DECLARE_int32(logbufsecs);
// Log suppression level: messages logged at a lower level than this
// are suppressed.
DECLARE_int32(minloglevel);
// If specified, logfiles are written into this directory instead of the
// default logging directory.
DECLARE_string(log_dir);
// Sets the path of the directory into which to put additional links
// to the log files.
DECLARE_string(log_link);
DECLARE_int32(v); // in vlog_is_on.cc
// Sets the maximum log file size (in MB).
DECLARE_int32(max_log_size);
// Sets whether to avoid logging to the disk if the disk is full.
DECLARE_bool(stop_logging_if_full_disk);
int64 base_num_infos = LogMessage::num_messages(GLOG_INFO); //INFO 级别日志数量
int64 base_num_warning = LogMessage::num_messages(GLOG_WARNING); //WARNING级别日志数量
int64 base_num_errors = LogMessage::num_messages(GLOG_ERROR); //ERROR级别日志数量
for ( int i = 0; i < 10; ++i ) {
int old_errno = errno;
errno = i;
PLOG_EVERY_N(ERROR, 2) << "Plog every 2, iteration " << COUNTER;
errno = old_errno;
LOG_EVERY_N(ERROR, 3) << "Log every 3, iteration " << COUNTER << endl;
LOG_EVERY_N(ERROR, 4) << "Log every 4, iteration " << COUNTER << endl;
LOG_IF_EVERY_N(WARNING, true, 5) << "Log if every 5, iteration " << COUNTER;
LOG_IF_EVERY_N(WARNING, false, 3)
<< "Log if every 3, iteration " << COUNTER;
LOG_IF_EVERY_N(INFO, true, 1) << "Log if every 1, iteration " << COUNTER;
LOG_IF_EVERY_N(ERROR, (i < 3), 2)
<< "Log if less than 3 every 2, iteration " << COUNTER;
}
LOG_IF(WARNING, true) << "log_if this";
LOG_IF(WARNING, false) << "don't log_if this";
DLOG(INFO)<<"ONLY PRINT FOR DEBUG COMPILE";
DLOG_IF(INFO,true)<<"ONLY PRINT FOR DEBUG COMPILE";
DLOG_EVERY_N(INFO,1)<<"ONLY PRINT FOR DEBUG COMPILE";
DLOG_IF_EVERY_N(INFO,true,1)<<"ONLY PRINT FOR DEBUG COMPILE";
void GoogleVLogTest(int v)
{
fLI::FLAGS_v = v;
VLOG(1)<<"if FLAGS_v >1, printf info";
VLOG(3)<<"IF FLAGS_v > 3,printf info";
//VLOG_IF
//VLOG_EVERY_N
//VLOG_IF_EVERY_N
//DVLOG
//DVLOG_IF
}