首页 > 编程语言 >easylogging++的那些事(四)源码分析(二)日志记录宏(四)偶尔日志宏

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

时间:2022-11-29 01:55:38浏览次数:67  
标签:__ el CLOG LOG ++ 源码 base 日志 ELPP

目录

在上一篇我们介绍完了 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 宏前面已经介绍过了。

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

标签:__,el,CLOG,LOG,++,源码,base,日志,ELPP
From: https://www.cnblogs.com/DesignLife/p/16934294.html

相关文章

  • LevelDB源码剖析(3) Skiplist跳表
    1.背景什么是跳表?跳表是SortedMap的一种具体实现,是一种概率性的数据结构。跳表拥有SortedMap的所有功能,定位和红黑树类似,其和红黑树的区别在于优点:跳表的实现更加简单......
  • 深入理解Kubernetes 4A - Audit源码解析
    Overview本文是关于Kubernetes4A解析的第四章深入理解Kubernetes4A-Authentication源码解析深入理解Kubernetes4A-Authorization源码解析深入理解Kubernetes......
  • c++_makefile
    关于四个version的思考,既然makefile的使用是为了便捷,从刚开始第一个简版的makefile有什么用,到第二版可以用依赖来抽象出1$(TARGET)和$(OBJ)之间的关系2.o.cpp之间的关......
  • MYSQL之日志管理、备份与恢复
    一.MySQL日志管理MySQL的日志默认保存位置为/usr/local/mysql/dataMySQL的日志配置文件为/etc/my.cnf ,里面有个[mysqld]项修改配置文件:vim/etc/my.cnf[mysqld]......
  • Swift 2023:强调并发、泛型和 C++ 互操作性,开发 Swift 解析器
    AppleSwift团队的一名工程师兼语言工作组成员JohnMcCall在最新发布的一篇博客中介绍了Swift的2023年度计划。“Swift项目中有很多激动人心的工作正在进行,而且很......
  • cocos2d-x 是男人就下100层 附源码
    1.效果图:  玩法:一个不断下降的小人,点击屏幕的left或者right控制小人的移动方向,尽可能生存久些. 为什么要搞这个游戏呢?因为在2012年的8月份,我完成它的android版本,......
  • C++学习------cmath头文件的源码学习06
    函数族定义---双曲函数cosh---计算双曲余弦函数sinh---计算双曲正弦函数tanh---计算双曲正切函数acosh---计算双曲余弦面积asinh---计算双曲正弦面积atanh---计算双曲正切面......
  • C++引用和指针
    1、有时候要想搞清楚一条赋值语句到底是改变了指针的值还是改变了指针所指对象的值不太容易,最好的办法就是记住赋值永远改变的等号左边的对象,例如:*p=0,改变的是p所指对象的......
  • 图文结合带你搞懂MySQL日志之Redo Log(重做日志)
    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。作者:KAiTO往期文章:图文结合带你搞定MySQ......
  • 启动备库rac时,集群日志出现CRS-2765告警
    问题描述:先启动备库rac时,集群日志出现CRS-2765告警,集群备库无法打开.2022-11-2809:19:26.806:[crsd(2605)]CRS-2765:Resource'ora.net1.network'hasfailedonserver'......