glog和gflag是工程中常常用到的两个google的开源库,在这里一起介绍一下一些基本的用法。
1. Google glog
参考:官方文档
glog全称是Google Logging Library,是google的开源日志系统,它轻巧灵活且功能完善,实现了程序级别的日志管理。
Google glog定义了一系列宏来简化日志工作。你可以:
- 按严重级别记录日志
- 通过命令行管理日志行为
- 基于条件记录日志
- 当预期条件没有达到时终止程序
- 引入自定义日志级别
#include
int main(int argc, char* argv[]) {
// Initialize Google's logging library.
google::InitGoogleLogging(argv[0]);
// ...
LOG(INFO) << "Found " << num_cookies << " cookies";
}
1.1. 严重级别(Severity Level)
Glog所支持的日志级别包括:INFO
、WARNING
、ERROR
和FATAL
。当记录一个FATAL
级别的日志后,程序会自动终止。要注意的是,给定级别的信息不仅会记录在该级别的日志里,也会记录在更低级别的日志里。
FATAL
级别的日志仅在debug模式下(没有定义NDEBUG
宏时)才会记录FATAL
错误,在生产过程中,则会自动降级为ERROR
以避免程序自动终止。
除非另外声明,glog会默认将日志记录在/tmp/
路径下,例如 /tmp/hello_world.example.com.hamaji.log.INFO.20080709-222411.10474
。默认情况下,glog也会另外将ERROR
和FATAL
级别的信息输出至标准错误。
1.2. 设置标签(Flags)
如果电脑上也安装了Google gflags library,那configure
脚本也会自动检测并使用它,这将允许你通过命令行传输标签。例如:
./your_application --logtostderr=1
如果没安装gflags,则可以通过环境变量设置标签,比如:
GLOG_logtostderr=1 ./your_application
在程序里面,则可以通过修改全局变量FLAGS_*
来修改标签,比如:
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";
常见的标签有:
-
logtostderr
(bool
):输出至标准错误。 -
stderrthreshold
(int
,默认为2):复制级别大于设定值的的日志至标准错误。 -
minloglevel
(int
,默认为0) -
log_dir
(string
):日志文件输出的路径。
1.3. 按条件记录
- 按判断条件筛选:
LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
- 每隔多少输出一个:
LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
- 输出前N个:
LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
1.4. CHECK宏
在程序中,定期检查结果是否符合预期是及早发现错误的好方式。CHECK
宏提供了中断程序的方式,类似于assert
。
CHECK
会在条件为假时终止程序,不同于assert
,其不会受到NDEBUG
选项影响。
举例:
CHECK(fp->Write(x) == 4) << "Write failed!";
CHECK_NE(1, 2) << ": The world must be ending!";
CHECK_NOTNULL(some_ptr);
1.5. Verbose Logging
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";
此外--vmodule
选项可以控制不同模块的日志情况:
--vmodule=mapreduce=2,file=1,gfs*=3 --v=0
将会:
- Print VLOG(2) and lower messages from mapreduce.{h,cc}
- Print VLOG(1) and lower messages from file.{h,cc}
- Print VLOG(3) and lower messages from files prefixed with "gfs"
- Print VLOG(0) and lower messages from elsewhere
此外还有VLOG_IS_ON(n)
宏、VLOG_IF
、VLOG_EVERY_N
、VLOG_IF_EVERY_N
等。
1.6. 错误信息处理
可以使用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)
2. Google gflag
参考:官方文档
gflags是google使用的一个开源库,用于解析命令行标记。
2.1. 下载安装
git clone https://github.com/gflags/gflags.git
2.2. 定义Flags
示例:
#include
DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing");
DEFINE_string(languages, "english,french,german",
"comma-separated list of languages to offer in the 'lang' menu");
支持的flags类型:DEFINE_bool
,DEFINE_int32
,DEFINE_int64
,DEFINE_uint64
,DEFINE_double
,DEFINE_string
。
这些宏需要三个参数:标记的名字、默认值、说明。说明可以通过--help
选项显示。
Flag只要定义一次,可以在头文件中声明(例如DECLARE_bool(big_menu)
),这样其他的源文件可以通过include
这个头文件来使用同样的flag。
注意大多数函数定义在google
命名空间中。
2.3. 使用Flags
所有定义的flags都可以在程序中像正常的变量一样使用,只要添加前缀FLAGS_
。
例如:
if (FLAGS_consider_made_up_languages)
FLAGS_languages += ",klingon"; // implied by --consider_made_up_languages
if (FLAGS_languages.find("finnish") != string::npos)
HandleFinnish();
2.4. 解析命令行中的Flags
通常在main()
中使用:
gflags::ParseCommandLineFlags(&argc, &argv, true);
其中最后一个参数决定是否从argv
中移除flags,并修改argc
。
这样,可以在程序调用的时候控制flags:
./app_containing_foo --nobig_menu -languages="chinese,japanese,korean" ...