目录
- 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 flag
enum class Level : base::type::EnumType
{
/// @brief Generic level that represents all the levels. Useful when setting global configuration > for all levels
Global = 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 application
Debug = 4,
/// @brief Severe error information that will presumably abort application
Fatal = 8,
/// @brief Information representing errors in application but application will keep running
Error = 16,
/// @brief Useful when application has potentially harmful situations
Warning = 32,
/// @brief Information that can be highly useful and vary with verbose logging level.
Verbose = 64,
/// @brief Mainly useful to represent current progress of application
Info = 128,
/// @brief Represents unknown level
Unknown = 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
类实例的创建过程。