spdlog源码分析:格式化输出

spdlog可以设置自己的日志输出格式,这是通过pattern_formatter实现的,实现分3部分
1.预先定义好的支持的输出格式
2.格式化输出串的编译
3.日志输出时的格式化

spdlog提供了大约30种控制输出,比如

/*在日志中添加日志名*/
class name_formatter :public flag_formatter
{
    void format(details::log_msg& msg, const std::tm&) override
    {
        msg.formatted << *msg.logger_name;
    }
};
/*在日志中添加日志等级level*/
class level_formatter :public flag_formatter
{
    void format(details::log_msg& msg, const std::tm&) override
    {
        msg.formatted << level::to_str(msg.level);
    }
};
/*在日志中添加日志等级缩略字符*/
class short_level_formatter :public flag_formatter
{
    void format(details::log_msg& msg, const std::tm&) override
    {
        msg.formatted << level::to_short_str(msg.level);
    }
};

不一一列举具体代码可以在pattern_formatter_impl.h中查看。
这些日志信息是否输出,输出在日志的什么位置都是用过格式化字符串控制的,格式化字符串通过spdlog::logger::set_pattern设置,也可以通过spdlog::set_pattern更改所有日志的格式化输出。

inline void spdlog::logger::_set_pattern(const std::string& pattern)
{
    _formatter = std::make_shared<pattern_formatter>(pattern);
}

set_pattern会对格式化字符串进行简单的编译,加速格式化速度和记录格式化信息。编译后的信息存在一个队列中,格式化输出的时候就从头到尾遍历这个队列,输出对应数据到日志中。

/*格式化输出串的编译*/
inline void spdlog::pattern_formatter::compile_pattern(const std::string& pattern)
{
    auto end = pattern.end();
    std::unique_ptr<details::aggregate_formatter> user_chars;
    for (auto it = pattern.begin(); it != end; ++it)
    {
        if (*it == '%')
        {
            /*控制字符处理*/
            /*先把非控制字符放入队列_formatters*/
            if (user_chars) //append user chars found so far
                _formatters.push_back(std::move(user_chars));

            if (++it != end)
                /*生成控制字符对应的格式化输出对象,加入格式化输出队列中_formatters*/
                handle_flag(*it);
            else
                break;
        }
        else // chars not following the % sign should be displayed as is
        {
            /*记录非控制字符,这些字符在格式化输出的时候,保持原样输出*/
            if (!user_chars)
                user_chars = std::unique_ptr<details::aggregate_formatter>(new details::aggregate_formatter());
            user_chars->add_ch(*it);
        }
    }
    if (user_chars) //append raw chars found so far
    {
        _formatters.push_back(std::move(user_chars));
    }
}
比如格式化字符串"*** [%H] [thread %t] ***"生成的控制信息队列是
aggregate_formatter:输出*** [
H_formatter:输出小时
aggregate_formatter:输出] [thread 
t_formatter:输出线程id
aggregate_formatter:输出] ***

格式化信息队列_formatters生成好后就可以对日志进行控制输出了

inline void spdlog::pattern_formatter::format(details::log_msg& msg)
{
    try
    {
#ifndef SPDLOG_NO_DATETIME
        auto tm_time = details::os::localtime(log_clock::to_time_t(msg.time));
#else
        std::tm tm_time;
#endif
        /*遍历格式化信息队列,输出对应的数据*/
        for (auto &f : _formatters)
        {
            f->format(msg, tm_time);
        }
        /*写入日志行尾,details::os::eol就是"\n"*/
        //write eol
        msg.formatted.write(details::os::eol, details::os::eol_size);
    }
    catch(const fmt::FormatError& e)
    {
        throw spdlog_ex(fmt::format("formatting error while processing format string: {}", e.what()));
    }
}

你可能感兴趣的:(C-C++,spdlog)