CLOG 宏展开

  • Info 日志宏 CLOG(INFO, xxx)
  • Trace 日志宏 CLOG(TRACE, XXX)
  • Debug 日志宏 CLOG(DEBUG, XXX)
  • Fatal 日志宏 CLOG(FATAL, XXX)
  • Error 日志宏 CLOG(ERROR, XXX)
  • Warning 日志宏 CLOG(WARNING, XXX)

在 上一篇中我们分析了 easylogging++的 主流程,今天来看看日志记录宏中 CLOG 宏的实现。
在 easylogging++的 功能介绍 中我们详细介绍了日志记录宏的一些用法,现在我们来一一剖析这些宏的实现。
先看看 CLOG 宏,CLOG 宏定义如下:

  #define CLOG(LEVEL, ...)\C##LEVEL(el::base::Writer, el::base::DispatchAction::NormalLog, __VA_ARGS__)

其中 ## 是连字符,__VA_ARGS__ 原样替换 ...
LEVEL 为用户日志的日志级别,分为下面这些类型:

    /// @brief Represents enumeration for severity level used to determine level of logging////// @detail With Easylogging++, developers may disable or enable any level regardless of/// what the severity is. Or they can choose to log using hierarchical logging flagenum class Level : base::type::EnumType{/// @brief Generic level that represents all the levels. Useful when setting global configuration > for all levelsGlobal = 1,/// @brief Information that can be useful to back-trace certain events - mostly useful than debug > logs.Trace = 2,/// @brief Informational events most useful for developers to debug applicationDebug = 4,/// @brief Severe error information that will presumably abort applicationFatal = 8,/// @brief Information representing errors in application but application will keep runningError = 16,/// @brief Useful when application has potentially harmful situationsWarning = 32,/// @brief Information that can be highly useful and vary with verbose logging level.Verbose = 64,/// @brief Mainly useful to represent current progress of applicationInfo = 128,/// @brief Represents unknown levelUnknown = 1010};

Info 日志宏 CLOG(INFO, xxx)

    用个具体的例子就一目了然了:

    CLOG(INFO, "default");

    上面实际展开后为:

   CINFO(el::base::Writer, el::base::DispatchAction::NormalLog, "default");

    而 CINFO 是另外一个宏:

    #if ELPP_INFO_LOG#define CINFO(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Info, dispatchAction, __VA_ARGS__)#else#define CINFO(writer, dispatchAction, ...) el::base::NullWriter()#endif // ELPP_INFO_LOG

    ELPP_INFO_LOG 的定义如下:

    #if (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED))#define ELPP_INFO_LOG 1#else#define ELPP_INFO_LOG 0#endif // (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED))

    ELPP_DISABLE_INFO_LOGSELPP_LOGGING_ENABLED 用于启用 info 日志级别。

    ELPP_INFO_LOG 值为 0 时,直接就是 el:: base:: NullWriter(),创建了 el:: base:: NullWriter 对象,el:: base:: NullWriter 后面会解释,这里简单提一下,就是用于: 当日志被禁用的使用,表示不进行输出。
    ELPP_INFO_LOG 值为 1 时,上面的 CINFO(el::base::Writer, el::base::DispatchAction::NormalLog, "default"); 展开后为:

    ELPP_WRITE_LOG(el::base::Writer, el::Level::Info, el::base::DispatchAction::NormalLog, "default");

    而 ELPP_WRITE_LOG 也是一个宏:

    #define ELPP_WRITE_LOG(writer, level, dispatchAction, ...) \writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)

    进一步展开后:

    el::base::Writer(el::Level::Info, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength("default"), "default");

    其中 el_getVALength 也是一个宏:

    #if ELPP_COMPILER_MSVC#define ELPP_VARIADIC_FUNC_MSVC(variadicFunction, variadicArgs) variadicFunction variadicArgs#define ELPP_VARIADIC_FUNC_MSVC_RUN(variadicFunction, ...) ELPP_VARIADIC_FUNC_MSVC(variadicFunction, (__VA_ARGS__))#define el_getVALength(...) ELPP_VARIADIC_FUNC_MSVC_RUN(el_resolveVALength, 0, ##__VA_ARGS__, \10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)#else#if ELPP_COMPILER_CLANG#define el_getVALength(...) el_resolveVALength(0, __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)#else#define el_getVALength(...) el_resolveVALength(0, ##__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)#endif // ELPP_COMPILER_CLANG#endif // ELPP_COMPILER_MSVC

    因为可变参宏在不同平台的差异性,windows(ELPP_COMPILER_MSVC 宏)下需要经过多次中间替换。最终经过替换后看起来就是下面这样:

    el_resolveVALength(0, "default", 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);

    el_resolveVALength 也是一个宏:

    #define el_resolveVALength(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N

    在easylogging++的 宏定义 中介绍过 el_resolveVALength 宏,是用于获取可变参的数量( 目前源码当中最多只能获取的可变参数量限制在 10 个 )。
    这里通过可变参数量的变化,让这些占位参数分别对应不同的值,从而间接让 N 正好对应的值是可变参的数量 ,大家这里可以试试分别获取可变参数量在 0-10 之间的可变参的实际数量,比如这里的 N 正好对应 1,也就是可变参数量为 1。

    将 el_getVALength("default") 换成这个 N 的值 1,最终展开为:

    el::base::Writer(el::Level::Info, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

    到这里为止,所有的宏替换就完成了,实际相当于创建了 el:: base:: Writer 类的实例,还是个临时对象。

    其他日志级别宏的展开类似。

Trace 日志宏 CLOG(TRACE, XXX)

    用个具体的例子就一目了然了:

    CLOG(TRACE, "default");

    上面实际展开后为:

    CTRACE(el::base::Writer, el::base::DispatchAction::NormalLog, "default");

    而 CTRACE 是另外一个宏:

    #if ELPP_TRACE_LOG#define CTRACE(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Trace, dispatchAction, __VA_ARGS__)#else#define CTRACE(writer, dispatchAction, ...) el::base::NullWriter()#endif // ELPP_TRACE_LOG

    ELPP_TRACE_LOG 宏定义如下:

    #if (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED))#define ELPP_TRACE_LOG 1#else#define ELPP_TRACE_LOG 0#endif // (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED))

    ELPP_DISABLE_TRACE_LOGSELPP_LOGGING_ENABLED 用于启用 Trace 级别日志。

    ELPP_TRACE_LOG 宏值为 0 时,直接就是 el:: base:: NullWriter() 这个前面 Info 日志宏分析时,已经简单介绍过了。
    ELPP_TRACE_LOG 宏值为 1 时,上面的 CTRACE(el:: base:: Writer, el:: base:: DispatchAction:: NormalLog, "default") 展开后为:

    ELPP_WRITE_LOG(el::base::Writer, el::Level::Trace, el::base::DispatchAction::NormalLog, "default");

    而 ELPP_WRITE_LOG 宏前面介绍过了,这里直接展开:

    el::base::Writer(el::Level::Trace, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength("default"), "default");

    el_getVALength 宏前面 Info 级别日志宏已经介绍过了,表示可变参的数目,这里 el_getVALength("default") 值为 1,再次替换后:

    el::base::Writer(el::Level::Trace, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

    到这里为止,所有的宏替换就完成了,和 Info 级别日志宏一样,实际也是相当于创建了 el:: base:: Writer 类的实例,还是个临时对象。

Debug 日志宏 CLOG(DEBUG, XXX)

    用个具体的例子就一目了然了:

    CLOG(DEBUG, "default");

    上面实际展开后为:

    CDEBUG(el::base::Writer, el::base::DispatchAction::NormalLog, "default");

    而 CDEBUG 是另外一个宏:

    #if ELPP_DEBUG_LOG#define CDEBUG(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Debug, dispatchAction, __VA_ARGS__)#else#define CDEBUG(writer, dispatchAction, ...) el::base::NullWriter()#endif // ELPP_DEBUG_LOG

    ELPP_DEBUG_LOG 宏定义如下:

    #if (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED))#define ELPP_DEBUG_LOG 1#else#define ELPP_DEBUG_LOG 0#endif // (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED))

    ELPP_DISABLE_DEBUG_LOGS 宏和 ELPP_LOGGING_ENABLED 宏用于开启 Debug 级别日志。

    当 ELPP_DEBUG_LOG 宏值为 0 时,直接就是 el:: base:: NullWriter() 这个前面 Info 日志宏分析时,已经简单介绍过了。
    当 ELPP_DEBUG_LOG 宏值为 1 时,上面的 CDEBUG(el:: base:: Writer, el:: base:: DispatchAction:: NormalLog, "default") 展开后为:

    ELPP_WRITE_LOG(el::base::Writer, el::Level::Debug, el::base::DispatchAction::NormalLog, "default");

    而 ELPP_WRITE_LOG 宏前面介绍过了,这里直接展开:

    el::base::Writer(el::Level::Debug, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength("default"), "default");

    el_getVALength 宏前面 Info 级别日志宏已经介绍过了,表示可变参的数目,这里 el_getVALength("default") 值为 1,再次替换后:

    el::base::Writer(el::Level::Debug, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1,  "default");

    到这里为止,所有的宏替换就完成了,和 Info 级别日志宏一样,实际相当于创建了 el:: base:: Writer 类的实例,还是个临时对象。

Fatal 日志宏 CLOG(FATAL, XXX)

    用个具体的例子就一目了然了:

    CLOG(FATAL, "default");

    上面实际展开后为:

    CFATAL(el::base::Writer, el::base::DispatchAction::NormalLog, "default");

    而 CFATAL 是另外一个宏:

    #if ELPP_FATAL_LOG#define CFATAL(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Fatal, dispatchAction, __VA_ARGS__)#else#define CFATAL(writer, dispatchAction, ...) el::base::NullWriter()#endif  // ELPP_FATAL_LOG

    ELPP_FATAL_LOG 的定义如下:

    #if (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED))#define ELPP_FATAL_LOG 1#else#define ELPP_FATAL_LOG 0#endif  // (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED))

    ELPP_DISABLE_FATAL_LOGS 宏和 ELPP_LOGGING_ENABLED 宏用于启用 Fatal 级别日志。

    当 ELPP_FATAL_LOG 宏值为 0 时,直接就是 el:: base:: NullWriter() 这个前面 Info 日志宏分析时,已经简单介绍过了。
    当 ELPP_FATAL_LOG 宏值为 1 时,上面的 CFATAL(el:: base:: Writer, el:: base:: DispatchAction:: NormalLog, "default") 展开后为:

    ELPP_WRITE_LOG(el::base::Writer, el::Level::Debug, el::base::DispatchAction::NormalLog, "default");

    而 ELPP_WRITE_LOG 宏前面介绍过了,这里直接展开:

    el::base::Writer(el::Level::Fatal, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength("default"), "default");

    el_getVALength 宏前面 Info 级别日志宏已经介绍过了,表示可变参的数目,这里 el_getVALength("default") 值为 1,再次替换后:

    el::base::Writer(el::Level::Fatal, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

    到这里为止,所有的宏替换就完成了,和 Info 级别日志宏一样,实际相当于创建了 el:: base:: Writer 类的实例,还是个临时对象。

Error 日志宏 CLOG(ERROR, XXX)

    用个具体的例子就一目了然了:

    CLOG(ERROR, "default");

    上面实际展开后为:

    CERROR(el::base::Writer, el::base::DispatchAction::NormalLog, "default");

    而 CERROR 是另外一个宏:

    #if ELPP_ERROR_LOG#define CERROR(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Error, dispatchAction, __VA_ARGS__)#else#define CERROR(writer, dispatchAction, ...) el::base::NullWriter()#endif  // ELPP_ERROR_LOG

    ELPP_ERROR_LOG 的定义如下:

    #if (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED))#define ELPP_ERROR_LOG 1#else#define ELPP_ERROR_LOG 0#endif  // (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED))

    ELPP_DISABLE_ERROR_LOGS 宏和 ELPP_LOGGING_ENABLED 宏用于开启 Error 级别日志。

    当 ELPP_ERROR_LOG 宏值为 0 时,直接就是 el:: base:: NullWriter(), 这个前面 Info 日志宏分析时,已经简单介绍过了。
    当 ELPP_ERROR_LOG 宏值为 1 时,上面的 CERROR(el:: base:: Writer, el:: base:: DispatchAction:: NormalLog, "default") 展开后为:

    ELPP_WRITE_LOG(el::base::Writer, el::Level::Error, el::base::DispatchAction::NormalLog, "default");

    而 ELPP_WRITE_LOG 宏前面介绍过了,这里直接展开:

    el::base::Writer(el::Level::Error, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength("default"), "default");

    el_getVALength 宏前面 Info 级别日志宏已经介绍过了,表示可变参的数目,这里 el_getVALength("default") 值为 1,再次替换后:

    el::base::Writer(el::Level::Error, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1,  "default");

    到这里为止,所有的宏替换就完成了,和 Info 级别日志宏一样,实际相当于创建了 el:: base:: Writer 类的实例,还是个临时对象。

Warning 日志宏 CLOG(WARNING, XXX)

    用个具体的例子就一目了然了:

    CLOG(WARNING, "default");

    上面实际展开后为:

    CWARNING(el::base::Writer, el::base::DispatchAction::NormalLog, "default");

    而 CWARNING 是另外一个宏:

    #if ELPP_WARNING_LOG#define CWARNING(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Warning, dispatchAction, __VA_ARGS__)#else#define CWARNING(writer, dispatchAction, ...) el::base::NullWriter()#endif  // ELPP_WARNING_LOG

    ELPP_WARNING_LOG 宏定义如下:

    #if (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED))#define ELPP_WARNING_LOG 1#else#define ELPP_WARNING_LOG 0#endif  // (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED))

    ELPP_DISABLE_WARNING_LOGS 宏和 ELPP_LOGGING_ENABLED 宏用于开启 Error 级别日志。

    当 ELPP_WARNING_LOG 宏值为 0 时,直接就是 el:: base:: NullWriter() 这个前面 Info 日志宏分析时,已经简单介绍过了。
    当 ELPP_WARNING_LOG 宏值为 1 时,上面的 CWARNING(el:: base:: Writer, el:: base:: DispatchAction:: NormalLog, "default") 展开后为:

    ELPP_WRITE_LOG(el::base::Writer, el::Level::Warning, el::base::DispatchAction::NormalLog, "default");

    而 ELPP_WRITE_LOG 宏前面介绍过了,这里直接展开:

    el::base::Writer(el::Level::Warning, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength("default"), "default");

    el_getVALength 宏前面 Info 级别日志宏已经介绍过了,表示可变参的数目,这里 el_getVALength("default") 值为 1,再次替换后:

    el::base::Writer(el::Level::Warning, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1,  "default");

    到这里为止,所有的宏替换就完成了,和 Info 级别日志宏一样,实际相当于创建了 el:: base:: Writer 类的实例,还是个临时对象。

CLOG 宏的展开到这里就介绍完了,下一篇文章我们开始分析 el:: base:: Writer 类实例的创建过程。

easylogging++的那些事(四)源码分析(二)日志记录宏(一)CLOG宏(一)宏展开相关推荐

  1. easylogging++的那些事(四)源码分析(二)日志记录宏(一)CLOG宏(三)日志输出

    日志输出 Writer 析构函数 Writer::processDispatch 接口 Writer::triggerDispatch 接口 base::LogDispatcher::dispatch ...

  2. 【投屏】Scrcpy源码分析二(Client篇-连接阶段)

    Scrcpy源码分析系列 [投屏]Scrcpy源码分析一(编译篇) [投屏]Scrcpy源码分析二(Client篇-连接阶段) [投屏]Scrcpy源码分析三(Client篇-投屏阶段) [投屏]Sc ...

  3. 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 二 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  4. gSOAP 源码分析(二)

    gSOAP 源码分析(二) 2012-5-24 flyfish 一 gSOAP XML介绍 Xml的全称是EXtensible Markup Language.可扩展标记语言.仅仅是一个纯文本.适合用 ...

  5. Android Q 10.1 KeyMaster源码分析(二) - 各家方案的实现

    写在之前 这两篇文章是我2021年3月初看KeyMaster的笔记,本来打算等分析完KeyMaster和KeyStore以后再一起做成一系列贴出来,后来KeyStore的分析中断了,这一系列的文章就变 ...

  6. SpringBoot源码分析(二)之自动装配demo

    SpringBoot源码分析(二)之自动装配demo 文章目录 SpringBoot源码分析(二)之自动装配demo 前言 一.创建RedissonTemplate的Maven服务 二.创建测试服务 ...

  7. Nouveau源码分析(二):Nouveau结构体的基本框架

    Nouveau源码分析(二) 在讨论Nouveau对Nvidia设备的初始化前,我准备先说一下Nouveau结构体的基本框架 Nouveau的很多结构体都可以看作是C++中的类,之间有很多相似的东西, ...

  8. ENS最新合约源码分析二

    ENS(以太坊域名服务)智能合约源码分析二 0.简介 ​ 本次分享直接使用线上实际注册流程来分析最新注册以太坊域名的相关代码.本次主要分析最新的关于普通域名注册合约和普通域名迁移合约,短域名竞拍合约不 ...

  9. 【转】ABP源码分析二十四:Notification

    NotificationDefinition: 用于封装Notification Definnition 的信息.注意和Notification 的区别,如果把Notification看成是具体的消息 ...

最新文章

  1. 【其他】GIT常用原生命令
  2. 值得收藏的 14 个 Linux 下 CPU 监控工具
  3. SpringCloud 应用在 Kubernetes 上的最佳实践 — 诊断(线上联调)
  4. 因为sudoers权限而引起的sudo失效
  5. selenium 翻页_利用selenium实现自动翻页爬取某鱼数据
  6. python 廖雪峰数据分析统计服_廖雪峰python教程阅读量统计
  7. 【转】DICOM之Print!!!!!!!!!
  8. 最便宜iPad曝光 苹果给力了!
  9. 手机老是应用无响应是怎么回事?
  10. matlab polyfit次数上限_新年重磅福利!全国21座城市酒店、民宿不限次数免费住!1000+景区免费玩!...
  11. Chrome安装插件Hackbar
  12. 数据分析岗位需求分析
  13. Veeam备份的虚拟机恢复后遇到磁盘问题无法打开虚拟机
  14. 用C++实现小游戏之石头剪刀布
  15. 学习笔记图片从本地复制到csdn博客出现:外链图片转存失败:解决方法
  16. Canvas: trying to use a recycled bitmap android.graphics.Bitmap
  17. 手机停机后你们知道怎么打电话?教你鲜为人知的手机锦囊
  18. 一:以理论结合实践方式梳理前端 ES 6+ ——— ES 6+ 能干什么
  19. 100条人生哲理语句
  20. C-Cheating and Stealing_2021牛客暑期多校训练营5

热门文章

  1. python读取mat格式数据
  2. linux下的mnt/hgfs/的共享目录无法出现的解决方案
  3. 【毕设狗】【单片机毕业设计】基于单片机的室内空气质量检测系统的设计
  4. 李国文山东建筑大学计算机学院,刘萌-计算机科学与技术学院
  5. 基于java旅游网站设计计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署
  6. 神舟战神z8r9、z7r9、z9r9、z8r7、z9r7怎么样 神舟战神z8r9、z7r9、z9r9、z8r7、z9r7区别
  7. Java中的文件输入输出操作如何实现
  8. python中能被3整除的数_可被3整除的值
  9. PPT:如何设置ppt中超链接的访问和未访问的颜色?
  10. vue-quill-editor 字体样式失效