easylogging++的那些事(四)源码分析(二)日志记录宏(四)偶尔日志宏

在上一篇我们介绍完了 easylogging++的 条件日志宏,今天我们来看看偶尔日志宏的实现.

CLOG_EVERY_N 宏

宏展开

    CLOG_EVERY_N 宏定义如下:

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

    其中 ## 是连字符,__VA_ARGS__ 原样替换 ...

Info 日志宏 CLOG_EVERY_N(xxx, INFO, xxx)

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

CLOG_EVERY_N(3, INFO, "default");

    上面实际展开后为:

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

    CINFO_EVERY_N 也是一个宏:

#if ELPP_INFO_LOG
#define CINFO_EVERY_N(writer, occasion, dispatchAction, ...)\
    ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Info, dispatchAction, __VA_ARGS__)
#else
#define CINFO_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_INFO_LOG

    ELPP_INFO_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_INFO_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Info, dispatchAction, __VA_ARGS__)

    经过替换后为:

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

    ELPP_WRITE_LOG_EVERY_N 也是一个宏:

#define ELPP_WRITE_LOG_EVERY_N(writer, occasion, level, dispatchAction, ...) \
    ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion) &&             \
        writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)

    展开后为:

ELPP->validateEveryNCounter(__FILE__, __LINE__, 3) &&
    el::base::Writer(el::Level::Info, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength("default"), "default");

    el_getVALength 宏在 CLOG 宏展开 中已经详细分析过了,表示可变参的数目,这里 el_getVALength("default") 值为 1,再次替换后:

ELPP->validateEveryNCounter(__FILE__, __LINE__, 3) && 
    el::base::Writer(el::Level::Info, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

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

Trace 日志宏 CLOG_EVERY_N(xxx, TRACE, xxx)

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

CLOG_EVERY_N(3, TRACE, "default");

    上面的实际展开后为:

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

    CTRACE_EVERY_N 也是一个宏:

#if ELPP_TRACE_LOG
#define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...)\
    ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Trace, dispatchAction, __VA_ARGS__)
#else
#define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_TRACE_LOG

    ELPP_TRACE_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_TRACE_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Trace, dispatchAction, __VA_ARGS__)

    ELPP_WRITE_LOG_EVERY_N 宏在 Info 日志宏中已经分析过了,这里直接看最终展开的结果:

ELPP->validateEveryNCounter(__FILE__, __LINE__, 3) && 
    el::base::Writer(el::Level::Trace, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

Debug 日志宏 CLOG_EVERY_N(xxx, DEBUG, xxx)

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

CLOG_EVERY_N(3, DEBUG, "default");

    上面的实际展开后为:

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

    CDEBUG_EVERY_N 也是一个宏:

#if ELPP_DEBUG_LOG
#define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...)\
    ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Debug, dispatchAction, __VA_ARGS__)
#else
#define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_DEBUG_LOG

    ELPP_DEBUG_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_DEBUG_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Debug, dispatchAction, __VA_ARGS__)

    ELPP_WRITE_LOG_EVERY_N 宏在 Info 日志宏中已经分析过了,这里直接看最终展开的结果:

ELPP->validateEveryNCounter(__FILE__, __LINE__, 3) && 
    el::base::Writer(el::Level::Debug, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

Fatal 日志宏 CLOG_EVERY_N(xxx, FATAL, xxx)

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

CLOG_EVERY_N(3, FATAL, "default");

    上面的实际展开后为:

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

    CFATAL_EVERY_N 也是一个宏:

#if ELPP_FATAL_LOG
#define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...)\
    ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Fatal, dispatchAction, __VA_ARGS__)
#else
#define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_FATAL_LOG

    ELPP_FATAL_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_FATAL_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Fatal, dispatchAction, __VA_ARGS__)

    ELPP_WRITE_LOG_EVERY_N 宏在 Info 日志宏中已经分析过了,这里直接看最终展开的结果:

ELPP->validateEveryNCounter(__FILE__, __LINE__, 3) && 
    el::base::Writer(el::Level::Fatal, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

Error 日志宏 CLOG_EVERY_N(xxx, ERROR, xxx)

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

CLOG_EVERY_N(3, ERROR, "default");

    上面的实际展开后为:

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

    CERROR_EVERY_N 也是一个宏:

#if ELPP_ERROR_LOG
#define CERROR_EVERY_N(writer, occasion, dispatchAction, ...)\
    ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Error, dispatchAction, __VA_ARGS__)
#else
#define CERROR_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_ERROR_LOG

    ELPP_ERROR_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_ERROR_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Error, dispatchAction, __VA_ARGS__)

    ELPP_WRITE_LOG_EVERY_N 宏在 Info 日志宏中已经分析过了,这里直接看最终展开的结果:

ELPP->validateEveryNCounter(__FILE__, __LINE__, 3) && 
    el::base::Writer(el::Level::Error, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

Warning 日志宏 CLOG_EVERY_N(xxx, WARNING, xxx)

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

CLOG_EVERY_N(3, WARNING, "default");

    上面的实际展开后为:

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

    CWARNING_EVERY_N 也是一个宏:

#if ELPP_WARNING_LOG
#define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...)\
    ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Warning, dispatchAction, __VA_ARGS__)
#else
#define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_WARNING_LOG

    ELPP_WARNING_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_WARNING_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Warning, dispatchAction, __VA_ARGS__)

    ELPP_WRITE_LOG_EVERY_N 宏在 Info 日志宏中已经分析过了,这里直接看最终展开的结果:

ELPP->validateEveryNCounter(__FILE__, __LINE__, 3) && 
    el::base::Writer(el::Level::Warning, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

源码剖析

    上面所有日志级别宏的最终展开后的结果都类似,这个宏其实就是表示:
    当 ELPP->validateEveryNCounter(__FILE__, __LINE__, 3)true 时,执行 el::base::Writer 对象的创建和初始化。el::base::Writer 类我们在 CLOGWriter 对象的创建以及初始化日志输出日志信息的保存 已经仔细介绍过了,这里就不多说了。
    当 ELPP->validateEveryNCounter(__FILE__, __LINE__, 3)false 时,啥也不干。

    ELPP 宏是 easylogging++的全局管理类,其定义如下:

extern ELPP_EXPORT base::type::StoragePointer elStorage;
#define ELPP el::base::elStorage

    ELPP->validateEveryNCounter 的实现如下:

inline bool validateEveryNCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t occasion) 
{
    return hitCounters()->validateEveryN(filename, lineNumber, occasion);
}

    hitCounters() 返回的是指定文件指定行的用于是否记录日志的计数器。
    validateEveryN 的实现如下:

bool RegisteredHitCounters::validateEveryN(const char *filename, base::type::LineNumber lineNumber, std::size_t n)
{
    base::threading::ScopedLock scopedLock(lock());
    // 获取指定文件的指定行的统计次数
    base::HitCounter *counter = get(filename, lineNumber);
    if (counter == nullptr)
    {
        registerNew(counter = new base::HitCounter(filename, lineNumber));
    }
    // 统计次数超过阈值进行调整
    counter->validateHitCounts(n);
    // 给定的偶尔记日志的次数有效并且调整后的统计次数符合条件则返回真
    bool result = (n >= 1 && counter->hitCounts() != 0 && counter->hitCounts() % n == 0);
    return result;
}

    validateHitCounts 实现如下:

/// @brief Validates hit counts and resets it if necessary
inline void validateHitCounts(std::size_t n)
{
    // 统计次数超过阈值时进行调整
    if (m_hitCounts >= base::consts::kMaxLogPerCounter)
    {
        m_hitCounts = (n >= 1 ? base::consts::kMaxLogPerCounter % n : 0);
    }
    ++m_hitCounts;
}

CLOG_AFTER_N 宏

宏展开

    CLOG_AFTER_N 宏定义如下:

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

    其中 ## 是连字符,__VA_ARGS__ 原样替换 ...

Info 日志宏 CLOG_AFTER_N(xxx, INFO, xxx)

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

CLOG_AFTER_N(3, INFO, "default");

    上面实际展开后为:

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

    CINFO_AFTER_N 也是一个宏:

#if ELPP_INFO_LOG
#define CINFO_AFTER_N(writer, n, dispatchAction, ...)\
    ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__)
#else
#define CINFO_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_INFO_LOG

    ELPP_INFO_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_INFO_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__)

    经过替换后为:

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

    ELPP_WRITE_LOG_AFTER_N 也是一个宏:

#define ELPP_WRITE_LOG_AFTER_N(writer, n, level, dispatchAction, ...) \
    ELPP->validateAfterNCounter(__FILE__, __LINE__, n) &&             \
        writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)

    展开后为:

ELPP->validateAfterNCounter(__FILE__, __LINE__, 3) &&
    el::base::Writer(el::Level::Info, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength("default"), "default");

    el_getVALength 宏在 CLOG 宏展开 中已经详细分析过了,表示可变参的数目,这里 el_getVALength("default") 值为 1,再次替换后:

ELPP->validateAfterNCounter(__FILE__, __LINE__, 3) && 
    el::base::Writer(el::Level::Info, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

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

Trace 日志宏 CLOG_AFTER_N(xxx, TRACE, xxx)

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

CLOG_AFTER_N(3, TRACE, "default");

    上面实际展开后为:

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

    CTRACE_AFTER_N 也是一个宏:

#if ELPP_TRACE_LOG
#define CTRACE_AFTER_N(writer, n, dispatchAction, ...)\
    ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__)
#else
#define CTRACE_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_TRACE_LOG

    ELPP_TRACE_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_TRACE_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__)

    经过替换后为:

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

    ELPP_WRITE_LOG_AFTER_N 宏在 Info 日志宏中已经详细介绍过了,这里直接看最终展开后的结果:

ELPP->validateAfterNCounter(__FILE__, __LINE__, 3) && 
    el::base::Writer(el::Level::Trace, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

Debug 日志宏 CLOG_AFTER_N(xxx, DEBUG, xxx)

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

CLOG_AFTER_N(3, DEBUG, "default");

    上面实际展开后为:

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

    CDEBUG_AFTER_N 也是一个宏:

#if ELPP_DEBUG_LOG
#define CDEBUG_AFTER_N(writer, n, dispatchAction, ...)\
    ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__)
#else
#define CDEBUG_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_DEBUG_LOG

    ELPP_DEBUG_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_DEBUG_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__)

    经过替换后为:

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

    ELPP_WRITE_LOG_AFTER_N 宏在 Info 日志宏中已经详细介绍过了,这里直接看最终展开后的结果:

ELPP->validateAfterNCounter(__FILE__, __LINE__, 3) && 
    el::base::Writer(el::Level::Debug, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

Fatal 日志宏 CLOG_AFTER_N(xxx, FATAL, xxx)

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

CLOG_AFTER_N(3, FATAL, "default");

    上面实际展开后为:

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

    CFATAL_AFTER_N 也是一个宏:

#if ELPP_FATAL_LOG
#define CFATAL_AFTER_N(writer, n, dispatchAction, ...)\
    ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__)
#else
#define CFATAL_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_FATAL_LOG

    ELPP_FATAL_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_FATAL_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__)

    经过替换后为:

ELPP_WRITE_LOG_AFTER_N(el::base::Writer, 3, el::Level::Fatal, el::base::DispatchAction::NormalLog, "default");

    ELPP_WRITE_LOG_AFTER_N 宏在 Info 日志宏中已经详细介绍过了,这里直接看最终展开后的结果:

ELPP->validateAfterNCounter(__FILE__, __LINE__, 3) && 
    el::base::Writer(el::Level::Fatal, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

Error 日志宏 CLOG_AFTER_N(xxx, ERROR, xxx)

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

CLOG_AFTER_N(3, ERROR, "default");

    上面实际展开后为:

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

    CERROR_AFTER_N 也是一个宏:

#if ELPP_ERROR_LOG
#define CERROR_AFTER_N(writer, n, dispatchAction, ...)\
    ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__)
#else
#define CERROR_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_ERROR_LOG

    ELPP_ERROR_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_ERROR_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__)

    经过替换后为:

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

    ELPP_WRITE_LOG_AFTER_N 宏在 Info 日志宏中已经详细介绍过了,这里直接看最终展开后的结果:

ELPP->validateAfterNCounter(__FILE__, __LINE__, 3) && 
    el::base::Writer(el::Level::Error, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

Warning 日志宏 CLOG_AFTER_N(xxx, WARNING, xxx)

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

CLOG_AFTER_N(3, WARNING, "default");

    上面实际展开后为:

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

    CWARNING_AFTER_N 也是一个宏:

#if ELPP_WARNING_LOG
#define CWARNING_AFTER_N(writer, n, dispatchAction, ...)\
    ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__)
#else
#define CWARNING_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_WARNING_LOG

    ELPP_WARNING_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_WARNING_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__)

    经过替换后为:

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

    ELPP_WRITE_LOG_AFTER_N 宏在 Info 日志宏中已经详细介绍过了,这里直接看最终展开后的结果:

ELPP->validateAfterNCounter(__FILE__, __LINE__, 3) && 
    el::base::Writer(el::Level::Warning, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

源码剖析

    上面所有日志级别宏的最终展开后的结果都类似,这个宏其实就是表示:

    当 ELPP->validateAfterNCounter(__FILE__, __LINE__, 3)true 时,执行 el::base::Writer 对象的创建和初始化。el::base::Writer 类我们在 CLOGWriter 对象的创建以及初始化日志输出日志信息的保存 已经仔细介绍过了,这里就不多说了。
    当 ELPP->validateAfterNCounter(__FILE__, __LINE__, 3)false 时,啥也不干。

    ELPP 宏在前面已经介绍过了,是 easylogging++的全局管理类。
    ELPP->validateAfterNCounter 的实现如下:

inline bool validateAfterNCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t n) 
{
    return hitCounters()->validateAfterN(filename, lineNumber, n);
}

    hitCounters() 返回的是指定文件指定行的用于是否记录日志的计数器。
    validateAfterN 的实现如下:

/// @brief Validates counter for hits >= N, i.e, registers new if does not exist otherwise updates original one
/// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned
bool RegisteredHitCounters::validateAfterN(const char* filename, base::type::LineNumber lineNumber, std::size_t n) 
{
   base::threading::ScopedLock scopedLock(lock());
   //获取指定文件的指定行的统计次数
   base::HitCounter* counter = get(filename, lineNumber);
   if (counter == nullptr) 
   {
       registerNew(counter = new base::HitCounter(filename, lineNumber));
   }
   // Do not use validateHitCounts here since we do not want to reset counter here
   // Note the >= instead of > because we are incrementing
   // after this check
   if (counter->hitCounts() >= n)
       return true;
   counter->increment();
   return false;
}

    increment 的实现如下:

inline void increment(void) 
{
    ++m_hitCounts;
}

    实现很简单,没什么好多说的。

CLOG_N_TIMES 宏

宏展开

    CLOG_N_TIMES 宏定义如下:

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

    其中 ## 是连字符,__VA_ARGS__ 原样替换 ...

Info 日志宏 CLOG_N_TIMES(xxx, INFO, xxx)

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

CLOG_N_TIMES(3, INFO, "default");

    上面实际展开后为:

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

    CINFO_N_TIMES 也是一个宏:

#if ELPP_INFO_LOG
#define CINFO_N_TIMES(writer, n, dispatchAction, ...)\
    ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__)
#else
#define CINFO_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_INFO_LOG

    ELPP_INFO_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_INFO_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__)

    经过替换后为:

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

    ELPP_WRITE_LOG_N_TIMES 也是一个宏:

#define ELPP_WRITE_LOG_N_TIMES(writer, n, level, dispatchAction, ...) \
    ELPP->validateNTimesCounter(__FILE__, __LINE__, n) && \
        writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)

    展开后为:

ELPP->validateNTimesCounter(__FILE__, __LINE__, 3) &&
    el::base::Writer(el::Level::Info, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(el_getVALength("default"), "default");

    el_getVALength 宏在 CLOG 宏展开 中已经详细分析过了,表示可变参的数目,这里 el_getVALength("default") 值为 1,再次替换后:

ELPP->validateNTimesCounter(__FILE__, __LINE__, 3) &&
    el::base::Writer(el::Level::Info, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

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

Trace 日志宏 CLOG_N_TIMES(xxx, TRACE, xxx)

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

CLOG_N_TIMES(3, TRACE, "default");

    上面实际展开后为:

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

    CTRACE_N_TIMES 也是一个宏:

#if ELPP_TRACE_LOG
#define CTRACE_N_TIMES(writer, n, dispatchAction, ...)\
    ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__)
#else
#define CTRACE_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_TRACE_LOG

    ELPP_TRACE_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_TRACE_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__)

    经过替换后为:

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

    ELPP_WRITE_LOG_N_TIMES 宏在 Info 日志宏中已经详细介绍过了,这里直接看最终最终展开的结果:

ELPP->validateNTimesCounter(__FILE__, __LINE__, 3) &&
    el::base::Writer(el::Level::Trace, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

Debug 日志宏 CLOG_N_TIMES(xxx, DEBUG, xxx)

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

CLOG_N_TIMES(3, DEBUG, "default");

    上面实际展开后为:

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

    CDEBUG_N_TIMES 也是一个宏:

#if ELPP_DEBUG_LOG
#define CDEBUG_N_TIMES(writer, n, dispatchAction, ...)\
    ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__)
#else
#define CDEBUG_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_DEBUG_LOG

    ELPP_DEBUG_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_DEBUG_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__)

    经过替换后为:

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

    ELPP_WRITE_LOG_N_TIMES 宏在 Info 日志宏中已经详细介绍过了,这里直接看最终最终展开的结果:

ELPP->validateNTimesCounter(__FILE__, __LINE__, 3) &&
    el::base::Writer(el::Level::Debug, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

Fatal 日志宏 CLOG_N_TIMES(xxx, FATAL, xxx)

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

CLOG_N_TIMES(3, FATAL, "default");

    上面实际展开后为:

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

    CFATAL_N_TIMES 也是一个宏:

#if ELPP_FATAL_LOG
#define CFATAL_N_TIMES(writer, n, dispatchAction, ...)\
    ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__)
#else
#define CFATAL_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_FATAL_LOG

    ELPP_FATAL_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_FATAL_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__)

    经过替换后为:

ELPP_WRITE_LOG_N_TIMES(el::base::Writer, 3, el::Level::Fatal, el::base::DispatchAction::NormalLog, "default");

    ELPP_WRITE_LOG_N_TIMES 宏在 Info 日志宏中已经详细介绍过了,这里直接看最终最终展开的结果:

ELPP->validateNTimesCounter(__FILE__, __LINE__, 3) &&
    el::base::Writer(el::Level::Fatal, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

Error 日志宏 CLOG_N_TIMES(xxx, ERROR, xxx)

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

CLOG_N_TIMES(3, ERROR, "default");

    上面实际展开后为:

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

    CERROR_N_TIMES 也是一个宏:

#if ELPP_ERROR_LOG
#define CERROR_N_TIMES(writer, n, dispatchAction, ...)\
    ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__)
#else
#define CERROR_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_ERROR_LOG

    ELPP_ERROR_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_ERROR_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__)

    经过替换后为:

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

    ELPP_WRITE_LOG_N_TIMES 宏在 Info 日志宏中已经详细介绍过了,这里直接看最终最终展开的结果:

ELPP->validateNTimesCounter(__FILE__, __LINE__, 3) &&
    el::base::Writer(el::Level::Error, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

Warning 日志宏 CLOG_N_TIMES(xxx, WARNING, xxx)

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

CLOG_N_TIMES(3, WARNING, "default");

    上面实际展开后为:

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

    CWARNING_N_TIMES 也是一个宏:

#if ELPP_WARNING_LOG
#define CWARNING_N_TIMES(writer, n, dispatchAction, ...)\
    ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__)
#else
#define CWARNING_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
#endif  // ELPP_WARNING_LOG

    ELPP_WARNING_LOG 宏和 el::base::NullWriter 类在 CLOG 宏展开 中已经介绍过了,这里就不多说了。
    这里我们直接看 ELPP_WARNING_LOG 宏值为 1 的情况:

ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__)

    经过替换后为:

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

    ELPP_WRITE_LOG_N_TIMES 宏在 Info 日志宏中已经详细介绍过了,这里直接看最终最终展开的结果:

ELPP->validateNTimesCounter(__FILE__, __LINE__, 3) &&
    el::base::Writer(el::Level::Warning, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(1, "default");

源码剖析

    上面所有日志级别宏的最终展开后的结果都类似,这个宏其实就是表示:

    当 ELPP->validateNTimesCounter(__FILE__, __LINE__, 3) 为真时,执行 el::base::Writer 对象的创建和初始化。el::base::Writer 类我们在 CLOGWriter 对象的创建以及初始化日志输出日志信息的保存 已经仔细介绍过了,这里就不多说了。
    当 ELPP->validateNTimesCounter(__FILE__, __LINE__, 3) 为假时,啥也不干。

    ELPP 宏在前面已经介绍过了,是 easylogging++的全局管理类。
    ELPP->validateNTimesCounter 的实现如下:

inline bool validateNTimesCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t n) 
{
    return hitCounters()->validateNTimes(filename, lineNumber, n);
}

    hitCounters() 返回的是指定文件指定行的用于是否记录日志的计数器。
    validateNTimes 的实现如下:

/// @brief Validates counter for hits are <= n, i.e, registers new if does not exist otherwise updates original one
/// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned
bool RegisteredHitCounters::validateNTimes(const char* filename, base::type::LineNumber lineNumber, std::size_t n) 
{
    base::threading::ScopedLock scopedLock(lock());
    base::HitCounter* counter = get(filename, lineNumber);
    if (counter == nullptr) 
    {
        registerNew(counter = new base::HitCounter(filename, lineNumber));
    }
    //increment接口在前面 CLOG_AFTER_N宏中已经介绍过了
    counter->increment();
    // Do not use validateHitCounts here since we do not want to reset counter here
    if (counter->hitCounts() <= n)
        return true;
    return false;
}

    实现很简单,没什么好多说的。

CSYSLOG_EVERY_N 宏

    CSYSLOG_EVERY_N 定义如下:

#define CSYSLOG_EVERY_N(n, LEVEL, ...) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)

    C##LEVEL##_EVERY_N 相关宏前面已经多次介绍过了。

CSYSLOG_AFTER_N 宏

    CSYSLOG_AFTER_N 定义如下:

#define CSYSLOG_AFTER_N(n, LEVEL, ...) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)

    C##LEVEL##_AFTER_N 相关宏前面已经多次介绍过了。

CSYSLOG_N_TIMES 宏

    CSYSLOG_N_TIMES 定义如下:

#define CSYSLOG_N_TIMES(n, LEVEL, ...) C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)

    C##LEVEL##_N_TIMES 相关宏前面已经多次介绍过了。

LOG_EVERY_N 宏

    LOG_EVERY_N 定义如下:

#define LOG_EVERY_N(n, LEVEL) CLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)

    CLOG_EVERY_N 宏前面已经介绍过了。

LOG_AFTER_N 宏

    LOG_AFTER_N 定义如下:

#define LOG_AFTER_N(n, LEVEL) CLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)

    CLOG_AFTER_N 宏前面已经介绍过了。

LOG_N_TIMES 宏

    LOG_N_TIMES 定义如下:

#define LOG_N_TIMES(n, LEVEL) CLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)

    CLOG_N_TIMES 宏前面已经介绍过了。

SYSLOG_EVERY_N 宏

    SYSLOG_EVERY_N 定义如下:

#define SYSLOG_EVERY_N(n, LEVEL) CSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId)

    CSYSLOG_EVERY_N 宏前面已经介绍过了。

SYSLOG_AFTER_N 宏

    SYSLOG_AFTER_N 定义如下:

#define SYSLOG_AFTER_N(n, LEVEL) CSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId)

    CSYSLOG_AFTER_N 宏前面已经介绍过了。

SYSLOG_N_TIMES 宏

    SYSLOG_N_TIMES 定义如下:

#define SYSLOG_N_TIMES(n, LEVEL) CSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId)

    CSYSLOG_N_TIMES 宏前面已经介绍过了。

至此,偶尔日志宏就介绍完了,下一篇我们开始介绍检查宏。

posted @ 2022-11-29 01:41  节奏自由  阅读(88)  评论(0编辑  收藏  举报