easylogging++的那些事(四)源码分析(二)日志记录宏(一)CLOG宏(一)宏展开
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_LOGS
和ELPP_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_LOGS
和ELPP_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宏(一)宏展开相关推荐
- easylogging++的那些事(四)源码分析(二)日志记录宏(一)CLOG宏(三)日志输出
日志输出 Writer 析构函数 Writer::processDispatch 接口 Writer::triggerDispatch 接口 base::LogDispatcher::dispatch ...
- 【投屏】Scrcpy源码分析二(Client篇-连接阶段)
Scrcpy源码分析系列 [投屏]Scrcpy源码分析一(编译篇) [投屏]Scrcpy源码分析二(Client篇-连接阶段) [投屏]Scrcpy源码分析三(Client篇-投屏阶段) [投屏]Sc ...
- 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 二 )
Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...
- gSOAP 源码分析(二)
gSOAP 源码分析(二) 2012-5-24 flyfish 一 gSOAP XML介绍 Xml的全称是EXtensible Markup Language.可扩展标记语言.仅仅是一个纯文本.适合用 ...
- Android Q 10.1 KeyMaster源码分析(二) - 各家方案的实现
写在之前 这两篇文章是我2021年3月初看KeyMaster的笔记,本来打算等分析完KeyMaster和KeyStore以后再一起做成一系列贴出来,后来KeyStore的分析中断了,这一系列的文章就变 ...
- SpringBoot源码分析(二)之自动装配demo
SpringBoot源码分析(二)之自动装配demo 文章目录 SpringBoot源码分析(二)之自动装配demo 前言 一.创建RedissonTemplate的Maven服务 二.创建测试服务 ...
- Nouveau源码分析(二):Nouveau结构体的基本框架
Nouveau源码分析(二) 在讨论Nouveau对Nvidia设备的初始化前,我准备先说一下Nouveau结构体的基本框架 Nouveau的很多结构体都可以看作是C++中的类,之间有很多相似的东西, ...
- ENS最新合约源码分析二
ENS(以太坊域名服务)智能合约源码分析二 0.简介 本次分享直接使用线上实际注册流程来分析最新注册以太坊域名的相关代码.本次主要分析最新的关于普通域名注册合约和普通域名迁移合约,短域名竞拍合约不 ...
- 【转】ABP源码分析二十四:Notification
NotificationDefinition: 用于封装Notification Definnition 的信息.注意和Notification 的区别,如果把Notification看成是具体的消息 ...
最新文章
- 【其他】GIT常用原生命令
- 值得收藏的 14 个 Linux 下 CPU 监控工具
- SpringCloud 应用在 Kubernetes 上的最佳实践 — 诊断(线上联调)
- 因为sudoers权限而引起的sudo失效
- selenium 翻页_利用selenium实现自动翻页爬取某鱼数据
- python 廖雪峰数据分析统计服_廖雪峰python教程阅读量统计
- 【转】DICOM之Print!!!!!!!!!
- 最便宜iPad曝光 苹果给力了!
- 手机老是应用无响应是怎么回事?
- matlab polyfit次数上限_新年重磅福利!全国21座城市酒店、民宿不限次数免费住!1000+景区免费玩!...
- Chrome安装插件Hackbar
- 数据分析岗位需求分析
- Veeam备份的虚拟机恢复后遇到磁盘问题无法打开虚拟机
- 用C++实现小游戏之石头剪刀布
- 学习笔记图片从本地复制到csdn博客出现:外链图片转存失败:解决方法
- Canvas: trying to use a recycled bitmap android.graphics.Bitmap
- 手机停机后你们知道怎么打电话?教你鲜为人知的手机锦囊
- 一:以理论结合实践方式梳理前端 ES 6+ ——— ES 6+ 能干什么
- 100条人生哲理语句
- C-Cheating and Stealing_2021牛客暑期多校训练营5
热门文章
- python读取mat格式数据
- linux下的mnt/hgfs/的共享目录无法出现的解决方案
- 【毕设狗】【单片机毕业设计】基于单片机的室内空气质量检测系统的设计
- 李国文山东建筑大学计算机学院,刘萌-计算机科学与技术学院
- 基于java旅游网站设计计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署
- 神舟战神z8r9、z7r9、z9r9、z8r7、z9r7怎么样 神舟战神z8r9、z7r9、z9r9、z8r7、z9r7区别
- Java中的文件输入输出操作如何实现
- python中能被3整除的数_可被3整除的值
- PPT:如何设置ppt中超链接的访问和未访问的颜色?
- vue-quill-editor 字体样式失效