easylogging++的那些事(四)源码分析(二)日志记录宏(一)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 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”);

而 是另外一个宏:
#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

的定义如下:
#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))

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

而 也是一个宏:
#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”);

其中 也是一个宏:
#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

因为可变参宏在不同平台的差异性,( 宏)下需要经过多次中间替换。最终经过替换后看起来就是下面这样:
el_resolveVALength(0, “default”, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);

也是一个宏:
#define el_resolveVALength(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, …) N

在easylogging++的 宏定义 中介绍过 宏,是用于获取可变参的数量( 目前源码当中最多只能获取的可变参数量限制在 10 个 )。
这里通过可变参数量的变化,让这些占位参数分别对应不同的值,从而间接让 N 正好对应的值是可变参的数量 ,大家这里可以试试分别获取可变参数量在 0-10 之间的可变参的实际数量,比如这里的 N 正好对应 1,也就是可变参数量为 1。
将 换成这个 N 的值 1,最终展开为:
el::base::Writer(el::Level::Info, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, “default”);

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

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

    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

值为 0 时,直接就是 ,创建了 对象, 后面会解释,这里简单提一下,就是用于: 当日志被禁用的使用,表示不进行输出。
值为 1 时,上面的 展开后为:

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

el_resolveVALength

将 换成这个 N 的值 1,最终展开为:

el_getVALength("default")
    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”);

而 是另外一个宏:
#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

宏定义如下:
#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))

和 用于启用 级别日志。
宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
宏值为 1 时,上面的 展开后为:
ELPP_WRITE_LOG(el::base::Writer, el::Level::Trace, el::base::DispatchAction::NormalLog, “default”);

而 宏前面介绍过了,这里直接展开:
el::base::Writer(el::Level::Trace, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength(“default”), “default”);

宏前面 级别日志宏已经介绍过了,表示可变参的数目,这里 值为 1,再次替换后:
el::base::Writer(el::Level::Trace, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, “default”);

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

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

    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

宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
宏值为 1 时,上面的 展开后为:

ELPP_TRACE_LOG
el:: base:: NullWriter()
Info
ELPP_TRACE_LOG
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");

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

el_getVALength
Info
el_getVALength("default")
    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”);

而 是另外一个宏:
#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

宏定义如下:
#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))

宏和 宏用于开启 级别日志。
当 宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:
ELPP_WRITE_LOG(el::base::Writer, el::Level::Debug, el::base::DispatchAction::NormalLog, “default”);

而 宏前面介绍过了,这里直接展开:
el::base::Writer(el::Level::Debug, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength(“default”), “default”);

宏前面 Info 级别日志宏已经介绍过了,表示可变参的数目,这里 值为 1,再次替换后:
el::base::Writer(el::Level::Debug, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, “default”);

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

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

    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

当 宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:

ELPP_DEBUG_LOG
el:: base:: NullWriter()
Info
ELPP_DEBUG_LOG
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");

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

el_getVALength
el_getVALength("default")
    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”);

而 是另外一个宏:
#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

的定义如下:
#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))

宏和 宏用于启用 级别日志。
当 宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:
ELPP_WRITE_LOG(el::base::Writer, el::Level::Debug, el::base::DispatchAction::NormalLog, “default”);

而 宏前面介绍过了,这里直接展开:
el::base::Writer(el::Level::Fatal, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength(“default”), “default”);

宏前面 Info 级别日志宏已经介绍过了,表示可变参的数目,这里 值为 1,再次替换后:
el::base::Writer(el::Level::Fatal, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, “default”);

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

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

    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

当 宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:

ELPP_FATAL_LOG
el:: base:: NullWriter()
Info
ELPP_FATAL_LOG
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");

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

el_getVALength
el_getVALength("default")
    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”);

而 是另外一个宏:
#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

的定义如下:
#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))

宏和 宏用于开启 级别日志。
当 宏值为 0 时,直接就是 , 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:
ELPP_WRITE_LOG(el::base::Writer, el::Level::Error, el::base::DispatchAction::NormalLog, “default”);

而 宏前面介绍过了,这里直接展开:
el::base::Writer(el::Level::Error, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct>> (el_getVALength(“default”), “default”);

宏前面 级别日志宏已经介绍过了,表示可变参的数目,这里 值为 1,再次替换后:
el::base::Writer(el::Level::Error, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, “default”);

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

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

    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

当 宏值为 0 时,直接就是 , 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:

ELPP_ERROR_LOG
el:: base:: NullWriter()
Info
ELPP_ERROR_LOG
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");

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

el_getVALength
Info
el_getVALength("default")
    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”);

而 是另外一个宏:
#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

宏定义如下:
#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))

宏和 宏用于开启 级别日志。
当 宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:
ELPP_WRITE_LOG(el::base::Writer, el::Level::Warning, el::base::DispatchAction::NormalLog, “default”);

而 宏前面介绍过了,这里直接展开:
el::base::Writer(el::Level::Warning, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct>> (el_getVALength(“default”), “default”);

宏前面 级别日志宏已经介绍过了,表示可变参的数目,这里 值为 1,再次替换后:
el::base::Writer(el::Level::Warning, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, “default”);

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

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

    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

当 宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:

ELPP_WARNING_LOG
el:: base:: NullWriter()
Info
ELPP_WARNING_LOG
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");

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

el_getVALength
Info
el_getVALength("default")
    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
————————
  • 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”);

而 是另外一个宏:
#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

的定义如下:
#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))

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

而 也是一个宏:
#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”);

其中 也是一个宏:
#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

因为可变参宏在不同平台的差异性,( 宏)下需要经过多次中间替换。最终经过替换后看起来就是下面这样:
el_resolveVALength(0, “default”, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);

也是一个宏:
#define el_resolveVALength(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, …) N

在easylogging++的 宏定义 中介绍过 宏,是用于获取可变参的数量( 目前源码当中最多只能获取的可变参数量限制在 10 个 )。
这里通过可变参数量的变化,让这些占位参数分别对应不同的值,从而间接让 N 正好对应的值是可变参的数量 ,大家这里可以试试分别获取可变参数量在 0-10 之间的可变参的实际数量,比如这里的 N 正好对应 1,也就是可变参数量为 1。
将 换成这个 N 的值 1,最终展开为:
el::base::Writer(el::Level::Info, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, “default”);

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

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

    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

值为 0 时,直接就是 ,创建了 对象, 后面会解释,这里简单提一下,就是用于: 当日志被禁用的使用,表示不进行输出。
值为 1 时,上面的 展开后为:

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

el_resolveVALength

将 换成这个 N 的值 1,最终展开为:

el_getVALength("default")
    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”);

而 是另外一个宏:
#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

宏定义如下:
#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))

和 用于启用 级别日志。
宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
宏值为 1 时,上面的 展开后为:
ELPP_WRITE_LOG(el::base::Writer, el::Level::Trace, el::base::DispatchAction::NormalLog, “default”);

而 宏前面介绍过了,这里直接展开:
el::base::Writer(el::Level::Trace, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength(“default”), “default”);

宏前面 级别日志宏已经介绍过了,表示可变参的数目,这里 值为 1,再次替换后:
el::base::Writer(el::Level::Trace, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, “default”);

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

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

    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

宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
宏值为 1 时,上面的 展开后为:

ELPP_TRACE_LOG
el:: base:: NullWriter()
Info
ELPP_TRACE_LOG
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");

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

el_getVALength
Info
el_getVALength("default")
    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”);

而 是另外一个宏:
#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

宏定义如下:
#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))

宏和 宏用于开启 级别日志。
当 宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:
ELPP_WRITE_LOG(el::base::Writer, el::Level::Debug, el::base::DispatchAction::NormalLog, “default”);

而 宏前面介绍过了,这里直接展开:
el::base::Writer(el::Level::Debug, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength(“default”), “default”);

宏前面 Info 级别日志宏已经介绍过了,表示可变参的数目,这里 值为 1,再次替换后:
el::base::Writer(el::Level::Debug, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, “default”);

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

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

    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

当 宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:

ELPP_DEBUG_LOG
el:: base:: NullWriter()
Info
ELPP_DEBUG_LOG
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");

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

el_getVALength
el_getVALength("default")
    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”);

而 是另外一个宏:
#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

的定义如下:
#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))

宏和 宏用于启用 级别日志。
当 宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:
ELPP_WRITE_LOG(el::base::Writer, el::Level::Debug, el::base::DispatchAction::NormalLog, “default”);

而 宏前面介绍过了,这里直接展开:
el::base::Writer(el::Level::Fatal, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength(“default”), “default”);

宏前面 Info 级别日志宏已经介绍过了,表示可变参的数目,这里 值为 1,再次替换后:
el::base::Writer(el::Level::Fatal, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, “default”);

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

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

    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

当 宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:

ELPP_FATAL_LOG
el:: base:: NullWriter()
Info
ELPP_FATAL_LOG
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");

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

el_getVALength
el_getVALength("default")
    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”);

而 是另外一个宏:
#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

的定义如下:
#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))

宏和 宏用于开启 级别日志。
当 宏值为 0 时,直接就是 , 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:
ELPP_WRITE_LOG(el::base::Writer, el::Level::Error, el::base::DispatchAction::NormalLog, “default”);

而 宏前面介绍过了,这里直接展开:
el::base::Writer(el::Level::Error, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct>> (el_getVALength(“default”), “default”);

宏前面 级别日志宏已经介绍过了,表示可变参的数目,这里 值为 1,再次替换后:
el::base::Writer(el::Level::Error, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, “default”);

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

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

    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

当 宏值为 0 时,直接就是 , 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:

ELPP_ERROR_LOG
el:: base:: NullWriter()
Info
ELPP_ERROR_LOG
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");

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

el_getVALength
Info
el_getVALength("default")
    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”);

而 是另外一个宏:
#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

宏定义如下:
#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))

宏和 宏用于开启 级别日志。
当 宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:
ELPP_WRITE_LOG(el::base::Writer, el::Level::Warning, el::base::DispatchAction::NormalLog, “default”);

而 宏前面介绍过了,这里直接展开:
el::base::Writer(el::Level::Warning, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct>> (el_getVALength(“default”), “default”);

宏前面 级别日志宏已经介绍过了,表示可变参的数目,这里 值为 1,再次替换后:
el::base::Writer(el::Level::Warning, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, “default”);

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

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

    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

当 宏值为 0 时,直接就是 这个前面 日志宏分析时,已经简单介绍过了。
当 宏值为 1 时,上面的 展开后为:

ELPP_WARNING_LOG
el:: base:: NullWriter()
Info
ELPP_WARNING_LOG
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");

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

el_getVALength
Info
el_getVALength("default")
    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