Chromium 日志机制
C++ 层
在chromium中,提供了多种打日志的宏(下面简称日志宏)。这些日志宏都可以接受一个流的参数。例如
LOG(INFO) << "Found " << num_cookies << " cookies";
剖析LOG
LOG是Chromium中最常用的日志宏。下面分析 LOG(INFO) « “this is a info msg”;
LOG相关宏的定义
#define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity))
#define LOG_IS_ON(severity) (::logging::ShouldCreateLogMessage(::logging::LOG_##severity))
#define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
#define COMPACT_GOOGLE_LOG_INFO COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)
#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \
::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_INFO, ##__VA_ARGS__)
#define LAZY_STREAM(stream, condition) !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream)
展开LOG(INFO)
(::logging::ShouldCreateLogMessage(::logging::LOG_INFO)) ? (void) 0 : \
::logging::LogMessageVoidify() & (::logging::LogMessage(__FILE__, __LINE__, LOG_INFO).stream()) \
<< "this is a info msg";
- 当 ::logging::ShouldCreateLogMessage(::logging::LOG_INFO) 为 false 时
LOG(INFO) << "this is a info msg"; // 当不满足打印日志的条件时,不会进行任何的求值以避免无意义的计算 // 等同于 (void) 0 << "this is a info msg";
- 当 ::logging::ShouldCreateLogMessage(::logging::LOG_INFO) 为 true 时
LOG(INFO) << "this is a info msg"; /* LogMessage 便是用于打印一条日志的类,其中 LogMessage::stream 方法返回一个类型为 std::ostream 的引用。 ::logging::LogMessageVoidify()& 为了使用 LogMessage::stream 返回来的引用, 避免编译时产生 "value computed is not used" 或者 "statement has no effect" 的警告 */ // 等同于 ::logging::LogMessageVoidify()&&stream << "this is a info msg";
其中 LogMessage 的析构函数,会做如下事情:如果定义有日志信息的钩子函数,那么就把日志信息交给钩子函数处理;如果没有,则会根据操作系统平台的不同来选择相应的处理方式。对于Android系统而言,会调用__android_log_write这个Android库函数,将日志以chromium这个tag来写入logcat;此外,如果启用了将日志写入文件的功能的话,也会执行相应的操作。
分类
这些日志宏可以从模式和行为上进行划分。在模式上,可以分为 “debug mode” 或者 “release mode”,这由gn参数的is_debug来进行控制。行为上可以划分为(D)LOG,(D)VLOG、(D)PLOG
debug mode 生效的日志宏
在 debug mode 下生效的日志宏,都是以字母D开头的,比如 DLOG、DVLOG、DPLOG、DCHEKC等等。在 “release mode” 下,上述的日志宏是不会被编译进去的。
DLOG(INFO) << "Found cookies";
DVLOG(1) << "I'm printed when you run the program with --v=1 or more"
DCHEKC(num_cookies > 10) << "Got lots of cookies";
DPLOG(ERROR) << "Couldn't do foo";
release mode 生效的日志宏
不以字母D开头的日志宏,在 debug mode 和 release mode 下都生效。比如LOG、VLOG、PLOG、CHEKC等等。
LOG(INFO) << "Found cookies";
LOG(1) << "I'm printed when you run the program with --v=1 or more"
CHEKC(num_cookies > 10) << "Got lots of cookies";
PLOG(ERROR) << "Couldn't do foo";
VLOG
这是一个 verbose level 的日志宏。如果符合打印日志条件,他会以 INFO 日志级别打印出来。使用方法如下:
VLOG(1) << "I'm printed when you run the program with --v=1 or more";
VLOG(2) << "I'm printed when you run the program with --v=2 or more";
对于 verbose level,我们可以使用 –vmodule 来对某个模块进行单独设置,也可以使用 –v 来进行全局设置。比如:
--vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0
- VLOG(2) and lower messages to be printed from profile.{h,cc}
- VLOG(1) and lower messages to be printed from icon_loader.{h,cc}
- VLOG(3) and lower messages to be printed from files prefixed with “browser”
- VLOG(4) and lower messages to be printed from files under a “chromeos” directory.
- VLOG(0) and lower messages to be printed from elsewhere
VLOG 相关的宏定义如下
#define VLOG_STREAM(verbose_level) \
::logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
#define VLOG(verbose_level) \
LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
PLOG
与 LOG 相比较,PLOG 会在日志的最后面自动加上最新的系统异常信息。在 Windows 系统中,是调用 GetLastError() 来获取系统异常信息。在 POSIX 系统中,是使用 errno。
PLOG 相关的宏定义如下
#if defined(OS_WIN)
#define PLOG_STREAM(severity) \
COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \
::logging::GetLastSystemErrorCode()).stream()
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
#define PLOG_STREAM(severity) \
COMPACT_GOOGLE_LOG_EX_ ## severity(ErrnoLogMessage, \
::logging::GetLastSystemErrorCode()).stream()
#endif
#define PLOG(severity) \
LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity))
可以看出底层是使用Win32ErrorLogMessage或者ErrnoLogMessage来实现的。而LOG是使用LogMessage来实现的。
JAVA层
在Java层,一般使用org.chromium.base代替android.util.log。org.chromium.base是android.util.log的封装,增加了 formatLog() 和 normalizeTag() 两个方法来分别格式化 TAG 和 message。