chromium源码学习-调试日志 LOG

在学习 chromium 源码时,我们经常需要增加调试日志,常见的用法一般是

// TurboNet.mm
  133
  134  LOG(INFO) << "TurboNet Engine started.";

在这里插入图片描述

其中 INFO 代表当前这条日志的级别,使用的时候就是输入 INFO 就行。接下来我们在探索下这个宏背后的内容。

一、基本用法

LOG 本身是一个宏:

#define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity))

我们逐个解开:

1、LOG_STREAM

#define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()

LOG_STREAM(severity) 会被转成具体 severity 对应的宏,例如 INFO 被转为宏 COMPACT_GOOGLE_LOG_INFO:

#define COMPACT_GOOGLE_LOG_INFO COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)

宏 COMPACT_GOOGLE_LOG_EX_INFO:

#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...)                  \
  ::logging::ClassName(__FILE__, __LINE__, ::logging::LOGGING_INFO, \
                       ##__VA_ARGS__)

ClassName 是 LogMessage,因此这里 COMPACT_GOOGLE_LOG_EX_INFO 代表的是 ::logging::LogMessage 类的构造方法,构造方法里调用 Init 方法初始化了一些调试信息比如文件名,行号,时间戳等,保存在 std::ostringstream 类型的成员变量 stream_ 中,LOG_STREAM 这个宏最终就是返回了这个 stream_对象。

2、LOG_IS_ON

#define LOG_IS_ON(severity)  (::logging::ShouldCreateLogMessage(::logging::LOGGING_##severity))
// severity 值如下
constexpr LogSeverity LOGGING_INFO = 0;
constexpr LogSeverity LOGGING_WARNING = 1;
constexpr LogSeverity LOGGING_ERROR = 2;
constexpr LogSeverity LOGGING_FATAL = 3;
constexpr LogSeverity LOGGING_DEBUG = 4;
constexpr LogSeverity LOGGING_NUM_SEVERITIES = 5;

bool ShouldCreateLogMessage(int severity) {
  if (severity < g_min_log_level)
    return false;

  // Return true here unless we know ~LogMessage won't do anything.
  return g_logging_destination != LOG_NONE || g_log_message_handler ||
         severity >= kAlwaysPrintErrorLevel;
}

// g_min_log_level
// 如果 SetMinLogLevel 未调用,g_min_log_level 默认为 LOGGING_FATAL
// 因此为了输出 LOGGING_INFO 级别的日志,需要将 g_min_log_level 的值设置为 <=-1 的值
void SetMinLogLevel(int level) {
  g_min_log_level = std::min(LOGGING_FATAL, level); 
}

3、LAZY_STREAM

#define LAZY_STREAM(stream, condition)  !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream)

如果 condition 为 false,则返回 nullptr,否则返回 stream 对象,这里 ::logging::LogMessageVoidify() 是一个空操作,该类内部重载了 & 运算符,对应一个空函数体,这么做是为了避免编译器警告 stream 未被使用。

二、进阶用法【未完待续】

VLOG、PLOG、DLOG

1、VLOG

整体跟 LOG 差不多,使用方式如下:

VLOG(1) << "Filter function already exists: " << filter_function
            << " with associated data: " << user_data;
#define VLOG(verbose_level) \
  LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))

// 除了对日志级别取负值,跟 LOG 一样,
#define VLOG_STREAM(verbose_level) \
  ::logging::LogMessage(__FILE__, __LINE__, -(verbose_level)).stream()

#define VLOG_IS_ON(verboselevel) \
  ((verboselevel) <= ::logging::GetVlogLevel(__FILE__))
template <size_t N>
int GetVlogLevel(const char (&file)[N]) {
  return GetVlogLevelHelper(file, N);
}

int GetVlogLevelHelper(const char* file, size_t N) {
  DCHECK_GT(N, 0U);
  // Note: |g_vlog_info| may change on a different thread during startup
  // (but will always be valid or nullptr).
  VlogInfo* vlog_info = g_vlog_info;
  return vlog_info ?
      vlog_info->GetVlogLevel(base::StringPiece(file, N - 1)) :
      GetVlogVerbosity();
}

三、日志输出

在 LogMessage::~LogMessage() 方法中,我们可以看到对各个系统平台的调试日志输出做了兼容,例如安卓(调用 __android_log_write)、iOS(调用__builtin_os_log_format)、Win(调用 OutputDebugStringA)等,因此鸿蒙的支持也需要在该方法中完成。
在这里插入图片描述

参考资料

相关推荐

  1. chromium 学习笔记

    2024-04-03 10:54:02       18 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-03 10:54:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-03 10:54:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-03 10:54:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-03 10:54:02       20 阅读

热门阅读

  1. 【linux】常用命令及选项含义+ 英文全称大全

    2024-04-03 10:54:02       17 阅读
  2. Python访问mysql与sqlite3数据库

    2024-04-03 10:54:02       18 阅读
  3. Mysql函数

    2024-04-03 10:54:02       17 阅读
  4. Android Studio 通过 WIFI 调试手机 app

    2024-04-03 10:54:02       17 阅读
  5. leetcode2810--故障键盘

    2024-04-03 10:54:02       19 阅读