摘抄修改自: http://www.cnblogs.com/tianyajuanke/archive/2013/02/22/2921850.html , 感谢原作者无私分享。
官方英文文档:http://google-glog.googlecode.com/svn/trunk/doc/glog.html
1.简介
google 出的一个C++轻量级日志库,支持以下功能:
◆ 参数设置,以命令行参数的方式设置标志参数来控制日志记录行为;
◆ 严重性分级,根据日志严重性分级记录日志;
◆ 可有条件地记录日志信息;
◆ 条件中止程序。丰富的条件判定宏,可预设程序终止条件;
◆ 异常信号处理。程序异常情况,可自定义异常处理过程;
◆ 支持debug功能;
◆ 自定义日志信息;
◆ 线程安全日志记录方式;
◆ 系统级日志记录;
◆ google perror风格日志信息;
◆ 精简日志字符串信息
2.安装
tar -zxvf glog-0.3.3.tar.gz
cd glog-0.3.3
./configure
make
make install
ldconfig
3.简单 Demo
vim glog.test.cpp
#include <glog/logging.h> int main(int argc,char* argv[]) { LOG(INFO) << "Hello,GLOG!"; }
g++ glog.test.cpp -lglog
执行时日志输出到 stderr.
4.错误级别
GLOG 有四个错误级别,枚举如下:
enum SeverityLevel { google::INFO = 0, google::WARNING = 1, google::ERROR = 2, google::FATAL = 3, };
5.Flags 设置:
在上面的简单 Demo 中,只能将日志输出到 stderr ,如果想将日志重定向到文件,需要:
google::InitGoogleLogging(argv[0]); /* GLOG代码 */ google::ShutdownGoogleLogging();
则默认运行会将日志输出到 /tmp 目录下(格式为 "<program name>.<hostname>.<user name>.log.<severity level>.<date>.<time>.<pid>")
运行参数可以在代码里通过加上 FLAGS_ 前缀来设置,如:
下面列出的都是默认值:
FLAGS_logtostderr = false; //是否将所有日志输出到stderr,而非文件FLAGS_alsologtostderr = false; //日志记录到文件的同时输出到strerrFLAGS_colorlogtostderr = false; //将彩色日志输出到stderrFLAGS_drop_log_memory = true; //日志写到文件的时候删除其在内存中的bufFLAGS_alsologtoemail = ""; //日志记录到文件的同时发送邮件到指定邮件地址FLAGS_log_prefix = true; //每行log加前缀FLAGS_minloglevel = google::INFO; //日志最低记录等级FLAGS_logbufsecs = 30; //日志最多缓存的秒数FLAGS_logbuflevel = google::INFO; //缓存日志的最低等级 , -1表示不缓存,0表示只缓存google::INFOFLAGS_logemaillevel = 999; //日志发送邮件的最低等级 , 0表示发送全部 , 3表示只发送google::FATALFLAGS_logmailer = "/bin/mail" ; //邮件发送的用户FLAGS_log_dir = ""; //设置日志文件输出目录
FLAGS_log_link = ""; //给日志目录的文件添加额外的链接FLAGS_max_log_size = 1800; //最大日志大小(MB), 如果设置为0将默认为1FLAGS_stop_logging_if_full_disk = false;//磁盘满停止记录日志FLAGS_log_backtrace_at = ""; //当记录"文件名:行号"的日志的时候触发一个backtraceFLAGS_v = 0; //记录所有 VLOG(m)中 m <= 这个值的自定义log , 这个标签会被 FLAGS_vmodule 覆盖FLAGS_vmodule = ""; //分模块(文件)设置VLOG(m)
日志信息的输出等级。命令格式为以逗号分开的“
<module name>=<log level>”表达式组成。其中
<module name>是“glob pattern”,支持通配符,<module name>不包括文件的扩展名(.h,.cc等)。
详细运行参数见 logging.cc 中的 DEFINE_ 开头的定义。
6.条件输出:
LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; //当条件满足时输出日志 LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie"; //google::COUNTER 记录该语句被执行次数,从1开始,在第一次运行输出日志之后,每隔 10 次再输出一次日志信息 LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER << "th big cookie"; //上述两者的结合,不过要注意,是先每隔 10 次去判断条件是否满足,如果是则输出日志;而不是当满足某条件的情况下,每隔 10 次输出一次日志信息。 LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie"; //当此语句执行的前 20 次都输出日志,然后不再输出
演示代码如下:
#include <glog/logging.h> int main(int argc,char* argv[]) { google::InitGoogleLogging(argv[0]); FLAGS_stderrthreshold=google::INFO; FLAGS_colorlogtostderr=true; for(int i = 1; i <= 100;i++) { LOG_IF(INFO,i==100)<<"LOG_IF(INFO,i==100) google::COUNTER="<<google::COUNTER<<" i="<<i; LOG_EVERY_N(INFO,10)<<"LOG_EVERY_N(INFO,10) google::COUNTER="<<google::COUNTER<<" i="<<i; LOG_IF_EVERY_N(WARNING,(i>50),10)<<"LOG_IF_EVERY_N(INFO,(i>50),10) google::COUNTER="<<google::COUNTER<<" i="<<i; LOG_FIRST_N(ERROR,5)<<"LOG_FIRST_N(INFO,5) google::COUNTER="<<google::COUNTER<<" i="<<i; } google::ShutdownGoogleLogging(); }
输出结果如下:
I1210 13:23:20.059790 6322 test01.cpp:11] LOG_EVERY_N(INFO,10) google::COUNTER=1 i=1 E1210 13:23:20.060670 6322 test01.cpp:13] LOG_FIRST_N(INFO,5) google::COUNTER=1 i=1 E1210 13:23:20.061272 6322 test01.cpp:13] LOG_FIRST_N(INFO,5) google::COUNTER=2 i=2 E1210 13:23:20.061337 6322 test01.cpp:13] LOG_FIRST_N(INFO,5) google::COUNTER=3 i=3 E1210 13:23:20.061393 6322 test01.cpp:13] LOG_FIRST_N(INFO,5) google::COUNTER=4 i=4 E1210 13:23:20.061450 6322 test01.cpp:13] LOG_FIRST_N(INFO,5) google::COUNTER=5 i=5 I1210 13:23:20.061506 6322 test01.cpp:11] LOG_EVERY_N(INFO,10) google::COUNTER=11 i=11 I1210 13:23:20.061529 6322 test01.cpp:11] LOG_EVERY_N(INFO,10) google::COUNTER=21 i=21 I1210 13:23:20.061553 6322 test01.cpp:11] LOG_EVERY_N(INFO,10) google::COUNTER=31 i=31 I1210 13:23:20.061575 6322 test01.cpp:11] LOG_EVERY_N(INFO,10) google::COUNTER=41 i=41 I1210 13:23:20.061599 6322 test01.cpp:11] LOG_EVERY_N(INFO,10) google::COUNTER=51 i=51 W1210 13:23:20.061621 6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10) google::COUNTER=51 i=51 I1210 13:23:20.061667 6322 test01.cpp:11] LOG_EVERY_N(INFO,10) google::COUNTER=61 i=61 W1210 13:23:20.061691 6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10) google::COUNTER=61 i=61 I1210 13:23:20.061738 6322 test01.cpp:11] LOG_EVERY_N(INFO,10) google::COUNTER=71 i=71 W1210 13:23:20.061761 6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10) google::COUNTER=71 i=71 I1210 13:23:20.061807 6322 test01.cpp:11] LOG_EVERY_N(INFO,10) google::COUNTER=81 i=81 W1210 13:23:20.061831 6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10) google::COUNTER=81 i=81 I1210 13:23:20.061877 6322 test01.cpp:11] LOG_EVERY_N(INFO,10) google::COUNTER=91 i=91 W1210 13:23:20.061902 6322 test01.cpp:12] LOG_IF_EVERY_N(INFO,(i>50),10) google::COUNTER=91 i=91 I1210 13:23:20.062140 6322 test01.cpp:10] LOG_IF(INFO,i==100) google::COUNTER=0 i=100
7.日志类型
LOG //内置日志 VLOG //自定义日志 DLOG //DEBUG模式可输出的日志 DVLOG //DEBUG模式可输出的自定义日志 SYSLOG //系统日志,同时通过 syslog() 函数写入到 /var/log/message 文件 PLOG //perror风格日志,设置errno状态并输出到日志中 RAW_LOG //线程安全的日志,需要#include <glog/raw_logging.h>
前六种的日志使用方法完全相同(包括条件日志输出),而 RAW_LOG 使用方法比较特殊,且不支持条件日志输出,另外不接受 colorlogtostderr 的颜色设置。自定义日志也不接受 colorlogtostderr 的颜色设置,另外其日志严重级别也为自定义数字,且与默认日志严重级别相反,数字越小严重级别越高。如:
1 #include <glog/logging.h> 2 #include <glog/raw_logging.h> 3 4 class GLogHelper 5 { 6 public: 7 GLogHelper(char* program) 8 { 9 google::InitGoogleLogging(program); 10 FLAGS_stderrthreshold=google::INFO; 11 FLAGS_colorlogtostderr=true; 12 FLAGS_v = 3; 13 } 14 ~GLogHelper() 15 { 16 google::ShutdownGoogleLogging(); 17 } 18 }; 19 20 int main(int argc,char* argv[]) 21 { 22 GLogHelper gh(argv[0]); 23 LOG(ERROR)<<"LOG"; 24 VLOG(3)<<"VLOG"; 25 DLOG(ERROR)<<"DLOG"; 26 DVLOG(3)<<"DVLOG"; 27 SYSLOG(ERROR)<<"SYSLOG"; 28 PLOG(ERROR)<<"PLOG"; 29 RAW_LOG(ERROR,"RAW_LOG"); 30 }
输出结果如下:
E1211 03:04:22.718116 13083 test01.cpp:23] LOG
I1211 03:04:22.719225 13083 test01.cpp:24] VLOG
E1211 03:04:22.719297 13083 test01.cpp:25] DLOG
I1211 03:04:22.719365 13083 test01.cpp:26] DVLOG
E1211 03:04:22.719391 13083 test01.cpp:27] SYSLOG
E1211 03:04:22.719650 13083 test01.cpp:28] PLOG: Success [0]
E1211 03:04:22.719650 13083 test01.cpp:29] RAW: RAW_LOG
8.CHECK 宏
当通过该宏指定的条件不成立的时候,程序会中止,并且记录对应的日志信息。功能类似于ASSERT,区别是 CHECK 宏不受 NDEBUG 约束,在 release 版中同样有效。
1.判定大小关系
CHECK_EQ, CHECK_NE, CHECK_LE, CHECK_LT, CHECK_GE, CHECK_GT,使用这些宏需要注意类型一致,如果出现类型不一致的,可使用static_cast转换。
2.判定指针是否为空
3.判定字符串是否相等
CHECK_STREQ
,
CHECK_STRNE
,
CHECK_STRCASEEQ
,
CHECK_STRCASENE
。可进行大小写敏感或不敏感字符串来分别判定。
4.
判定浮点是否相等或相近
CHECK_DOUBLE_EQ
,CHECK_NEAR。这两个宏都需要指定一个可容忍的偏差上限。
9.core dumped
通过 google::InstallFailureSignalHandler(); 即可注册,将 core dumped 信息输出到 stderr,如:
#include <glog/logging.h> #include <string> #include <fstream> //将信息输出到单独的文件和 LOG(ERROR) void SignalHandle(const char* data, int size) { std::ofstream fs("glog_dump.log",std::ios::app); std::string str = std::string(data,size); fs<<str; fs.close(); LOG(ERROR)<<str; } class GLogHelper { public: GLogHelper(char* program) { google::InitGoogleLogging(program); FLAGS_colorlogtostderr=true; google::InstallFailureSignalHandler(); //默认捕捉 SIGSEGV 信号信息输出会输出到 stderr,可以通过下面的方法自定义输出方式: google::InstallFailureWriter(&SignalHandle); } ~GLogHelper() { google::ShutdownGoogleLogging(); } }; void fun() { int* pi = new int; delete pi; pi = 0; int j = *pi; } int main(int argc,char* argv[]) { GLogHelper gh(argv[0]); fun(); }
输出的错误报告如下,可定位错误于 fun() 函数内:
E1211 06:07:04.787719 15444 test01.cpp:11] *** Aborted at 1386742024 (unix time) try "date -d @1386742024" if you are using GNU date ***
E1211 06:07:04.789120 15444 test01.cpp:11] PC: @ 0x401227 fun()
E1211 06:07:04.789481 15444 test01.cpp:11] *** SIGSEGV (@0x0) received by PID 15444 (TID 0x7f03ce478720) from PID 0; stack trace: ***
E1211 06:07:04.791168 15444 test01.cpp:11] @ 0x7f03cd505960 (unknown)
E1211 06:07:04.791453 15444 test01.cpp:11] @ 0x401227 fun()
E1211 06:07:04.791712 15444 test01.cpp:11] @ 0x40125b main
E1211 06:07:04.792908 15444 test01.cpp:11] @ 0x7f03cd4f1cdd __libc_start_main
E1211 06:07:04.793227 15444 test01.cpp:11] @ 0x400fc9 (unknown)
段错误 (core dumped)
如果不使用 google::InstallFailureSignalHandler(); 则只会输出 “段错误” 三个字,难于排查。
默认情况下,异常信息是输出到 stderr,通过InstallFailureWriter()可以改变输出目标。10.日志文件说明
如果可执行文件名为 "test",则将日志输出到文件后,还会生成 test.ERROR,test.WARNING,test.INFO 三个链接文件,分别链接到对应级别的日志文件。如果日志输出超过 FLAGS_max_log_size 设置的大小,则会分为多个文件存储,链接文件就会指向其中最新的对应级别的日志文件。所以当日志文件较多时,查看链接文件来查看最新日志挺方便的。
DLOG(INFO) << "Found cookies";
DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
DLOG_EVERY_N(INFO, 10) << "Got the " << COUNTER << "th cookie";
13.线程安全日志记录
除了提供了普通的日志记录宏,还提供SYSLOG, SYSLOG_IF,和 SYSLOG_EVERY_N宏,这些宏将日志信息通过syslog()函数记录到系统日志。
15.peror风格日志记录
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]
c, 导致冲突的ERROR标识符定义在文件“glog\log_severity.h”中,类型为const int,不过在里面还定义一个ERROR的字符串,所以在替换时要区别这两个标识符。此外Glog中的一些宏也需要小改,COMPACT_GOOGLE_LOG_ERROR需要改成COMPACT_GOOGLE_LOG_GERROR。
18.实用封装
GLogHelper.h 如下:
#include <glog/logging.h> #include <glog/raw_logging.h> //将信息输出到单独的文件和 LOG(ERROR) void SignalHandle(const char* data, int size); class GLogHelper { public: //GLOG配置: GLogHelper(char* program); //GLOG内存清理: ~GLogHelper(); };
GlogHelper.cpp 如下:
#include <stdlib.h> #include "GLogHelper.h" //配置输出日志的目录: #define LOGDIR "log" #define MKDIR "mkdir -p "LOGDIR //将信息输出到单独的文件和 LOG(ERROR) void SignalHandle(const char* data, int size) { std::string str = std::string(data,size); /* std::ofstream fs("glog_dump.log",std::ios::app); fs<<str; fs.close(); */ LOG(ERROR)<<str; //也可以直接在这里发送邮件或短信通知,不过这个方法是被回调多次的(每次回调只输出一行错误信息,所以如上面的记录到文件,也需要>以追加模式方可),所以这里发邮件或短信不是很适合,不过倒是可以调用一个 SHELL 或 PYTHON 脚本,而此脚本会先 sleep 3秒左右,然后将错 误信息通过邮件或短信发送出去,这样就不需要监控脚本定时高频率执行,浪费效率了。 } //GLOG配置: GLogHelper::GLogHelper(char* program) { system(MKDIR); google::InitGoogleLogging(program); google::SetStderrLogging(google::INFO); //设置级别高于 google::INFO 的日志同时输出到屏幕 FLAGS_colorlogtostderr=true; //设置输出到屏幕的日志显示相应颜色 //google::SetLogDestination(google::ERROR,"log/error_"); //设置 google::ERROR 级别的日志存储路径和文件名前缀 google::SetLogDestination(google::INFO,LOGDIR"/INFO_"); //设置 google::INFO 级别的日志存储路径和文件名前缀 google::SetLogDestination(google::WARNING,LOGDIR"/WARNING_"); //设置 google::WARNING 级别的日志存储路径和文件名前缀 google::SetLogDestination(google::ERROR,LOGDIR"/ERROR_"); //设置 google::ERROR 级别的日志存储路径和文件名前缀 FLAGS_logbufsecs =0; //缓冲日志输出,默认为30秒,此处改为立即输出 FLAGS_max_log_size =100; //最大日志大小为 100MB FLAGS_stop_logging_if_full_disk = true; //当磁盘被写满时,停止日志输出 google::SetLogFilenameExtension("91_"); //设置文件名扩展,如平台?或其它需要区分的信息 google::InstallFailureSignalHandler(); //捕捉 core dumped google::InstallFailureWriter(&SignalHandle); //默认捕捉 SIGSEGV 信号信息输出会输出到 stderr,可以通过下面的方法自定义输出>方式: } //GLOG内存清理: GLogHelper::~GLogHelper() { google::ShutdownGoogleLogging(); }
测试文件 test.cpp 如下:
#include "GLogHelper.h" int main(int argc,char* argv[]) { //要使用 GLOG ,只需要在 main 函数开始处添加这句即可 GLogHelper gh(argv[0]); LOG(INFO)<<"INFO"; LOG(ERROR)<<"ERROR"; }