在 easylogging++的那些事(四)源码分析(二)日志记录宏(一)CLOG宏(一)宏展开中我们对CLOG宏展开了,今天来看看日志记录宏中 CLOG 宏的实现。

从上面所有用户日志相关日志级别宏的最终展开结果可以看到: 都是创建了 el:: base:: Writer 类的实例,还是个临时对象。今天我们就来看看这个对象的创建过程。

el:: base:: Writer 类是日志记录的入口点。

构造函数

    el:: base:: Writer 的构造函数的定义:

    Writer(Level level, const char* file, base::type::LineNumber line,
        const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog,
        base::type::VerboseLevel verboseLevel = 0) :
        m_msg(nullptr), m_level(level), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel),
        m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) {}

    Writer(LogMessage* msg, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog) :
        m_msg(msg), m_level(msg != nullptr ? msg->level() : Level::Unknown),
        m_line(0), m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) {}

    相关成员变量:

    LogMessage* m_msg;   //主要用于作为其他类的成员或者函数参数,日志相关信息的wrapper类
    Logger* m_logger; //当前正在使用的日志记录器
    bool m_proceed //当前的日志是否需要处理
    base::MessageBuilder m_messageBuilder  //用于支持各种类型的日志输出
    base::DispatchAction m_dispatchAction  //调度动作:当前是记录用户日志还是syslog日志
    std::vector<std::string> m_loggerIds //当前日志所使用到的所有的日志记录器

    构造函数本身只是初始化了一些成员变量,没有做太多事情。

construct 接口

    el:: base:: Writerconstruct 接口的声明:

    Writer& construct(Logger* logger, bool needLock = true);
    Writer& construct(int count, const char* loggerIds, ...);

    根据 C++函数重载的匹配规则,是下面这个函数匹配上了:

    Writer& construct(int count, const char* loggerIds, ...);

    这个函数的定义如下:

    Writer &Writer::construct(int count, const char *loggerIds, ...)
    {
        // 判断是否支持多日志记录器输出,比如:使用形式:LOG(INFO, "default", "business");
        // 其中default和business是日志记录器ID,这样会分别使用default和business这两个日志记录器输出一条日志
        if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport))
        {
            // 正常可变参部分全是字符串类型,代表的是多个日志记录器
            va_list loggersList;
            va_start(loggersList, loggerIds);
            const char *id = loggerIds;
            // m_loggerIds是std::vector<std::string>,先调用reserve预留足够的空间可以避免vector动态扩容带来的性能损失
            m_loggerIds.reserve(count);
            for (int i = 0; i < count; ++i)
            {
                // 将可变参列表中的每个参数(日志记录器)依次加入m_loggerIds
                m_loggerIds.push_back(std::string(id));
                id = va_arg(loggersList, const char *);
            }
            va_end(loggersList);
            // 使用m_loggerIds当中的第一个记录器ID来初始化m_logger
            initializeLogger(m_loggerIds.at(0));
        }
        else
        {
            // 如果不支持多日志记录器输出的话,直接使用loggerIds来初始化m_logger
            initializeLogger(std::string(loggerIds));
        }
        // 初始化m_messageBuilder
        m_messageBuilder.initialize(m_logger);
        return *this;
    }

initializeLogger接口

    再来看看 initializeLogger 的实现。
    initializeLogger 的声明如下:

    void initializeLogger(const std::string& loggerId, bool lookup = true, bool needLock = true);

    initializeLogger 的定义如下:

    void Writer::initializeLogger(const std::string &loggerId, bool lookup, bool needLock)
    {
        if (lookup)
        {
            // 如果需要查找日志记录器的话,就先查找对应ID的日志记录器
            m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag >> (LoggingFlag::CreateLoggerAutomatically));
        }
    
        if (m_logger == nullptr)
        {
            // 当对应ID的日志记录器不存在时,获取默认的日志记录器
            {
                if (!ELPP->registeredLoggers()->has(std::string >> (base::consts::kDefaultLoggerId)))
                {
                    // Somehow default logger has been unregistered. Not good! Register again
                    ELPP->registeredLoggers()->get(std::string(base::consts::kDefaultLoggerId));
                }
            }
            // 利用默认的日志记录器记录调试日志
            Writer(Level::Debug, m_file, m_line, m_func).construct(1, >> base::consts::kDefaultLoggerId)
                << "Logger [" << loggerId << "] is not registered yet!";
            // 然后设置这条日志不处理
            m_proceed = false;
        }
        else
        {
            // 当对应ID的日志记录器存在时
            if (needLock)
            {
                // 当m_logger处理完这条日志后,会自动进行解锁
                m_logger->acquireLock(); // This should not be unlocked by checking m_proceed >>because
                                         // m_proceed can be changed by lines below
            }
            if (ELPP->hasFlag(LoggingFlag::HierarchicalLogging))
            {
                // 当分层日志记录时,日志为详细日志时,根据日志记录器对应的日志级别的启用配置来决>>定是当前的日志记录器否处理这条日志
                // 当日志不为详细日志时,当当前的日志级别大于或者等于全局基准日志级别>>(ELPP->m_loggingLevel)才处理日志
                m_proceed = m_level == Level::Verbose ? m_logger->enabled(m_level) : LevelHelper::castToInt(m_level) >= LevelHelper::castToInt (ELPP->m_loggingLevel);
            }
            else
            {
                // 当不分层日志记录时,根据日志记录器对应的日志级别的启用配置来决定当前的日志记录>>器是否处理这条日志
                m_proceed = m_logger->enabled(m_level);
            }
        }
    }

到这里为止,el:: base:: Writer 类对象的创建和初始化就介绍完了。

但我们发现了一个问题,自始至终没有看到真正写文件或者输出到终端或者输出到其他日志目的地的动作,那真实写日志的动作是在哪里触发的呢? 下一篇将为你揭晓。

原文地址:http://www.cnblogs.com/DesignLife/p/16926493.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性