boost.log教程:loggers

logger是用户接触最多的类

  • 可分为无保护和线程安全两类,线程安全的以_mt结尾
  • logger有窄字符和宽字符的,宽字符的以w开头,如wlogger_mt
  • logger类可复制,可创建的,可作为自定义类的成员
  • boost.log提供多种logger,参见网页

直接使用

如下即可:

#include <boost/log/trivial.hpp>

int main(int, char*[])
{
    BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
    BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
    BOOST_LOG_TRIVIAL(info) << "An informational severity message";
    BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
    BOOST_LOG_TRIVIAL(error) << "An error severity message";
    BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";

    return 0;
}

全局logger

BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::logger_mt)
  • my_logger是用户自定义的logger名
  • src::logger_mt是logger类型
  • 可以注册多个全局对象

boost.log还提供其他的宏

注册全局logger后,可通过以下语句获取该对象:

src::logger_mt& lg = my_logger::get(); // my_logger是自己注册的全局对象名

写logger

写log的方法是通用的,如下:

logging::record rec = lg.open_record(); // lg是logger对象,logging record见后文
if (rec)
{
    logging::record_ostream strm(rec);
    strm << "Hello, World!";
    strm.flush();
    lg.push_record(boost::move(rec));
}
  • open_record相当于调用了logging core的filter (如本页最开头的severity),通过检测才会返回有效的logging::record对象
  • push_record在logging::record对象在信息填写完成后将消息推送出去

以上代码有更简单的替换版本:

BOOST_LOG(lg) << "Hello, World!";

配合attribute写log

attribute添加在logger上和record上可实现自定义的效果,下例中:

  • RemoteAddress添加到logger上,所有由这个logger发出的record都可使用```RemoteAddress``标签
  • Message添加在record上,那就只有这一条record有这个attribute
class network_connection
{
    src::logger m_logger;
    logging::attribute_set::iterator m_remote_addr;

public:
    void on_connected(std::string const& remote_addr)
    {
        // Put the remote address into the logger to automatically attach it
        // to every log record written through the logger
        m_remote_addr = m_logger.add_attribute("RemoteAddress",
            attrs::constant< std::string >(remote_addr)).first;

        // The straightforward way of logging
        if (logging::record rec = m_logger.open_record())
        {
            rec.attribute_values().insert("Message",
                attrs::make_attribute_value(std::string("Connection established")));
            m_logger.push_record(boost::move(rec));
        }
    }
    void on_disconnected()
    {
        // The simpler way of logging: the above "if" condition is wrapped into a neat macro
        BOOST_LOG(m_logger) << "Connection shut down";

        // Remove the attribute with the remote address
        m_logger.remove_attribute(m_remote_addr);
    }
    void on_data_received(std::size_t size)
    {
        // Put the size as an additional attribute
        // so it can be collected and accumulated later if needed.
        // The attribute will be attached only to this log record.
        BOOST_LOG(m_logger) << logging::add_value("ReceivedSize", size) << "Some data received";
    }
    void on_data_sent(std::size_t size)
    {
        BOOST_LOG(m_logger) << logging::add_value("SentSize", size) << "Some data sent";
    }
};

Loggers 配合 severity

相关的类共有severity_loggerseverity_logger_mtwseverity_loggerwseverity_logger_mt4个。
这4个类都有Severity属性,在调用open_record函数时会先检查是否通过Severity属性检测,通过了就会返回record。
Severity属性说明:

  • int类型
  • 最好以0为起点,方便大小判断
  • 全局最好使用统一的级别
  • Severity可使用各种类型
// We define our own severity levels
enum severity_level
{
    normal,
    notification,
    warning,
    error,
    critical
};

void logging_function()
{
    // The logger implicitly adds a source-specific attribute 'Severity'
    // of type 'severity_level' on construction
    src::severity_logger< severity_level > slg;

    BOOST_LOG_SEV(slg, normal) << "A regular message";
    BOOST_LOG_SEV(slg, warning) << "Something bad is going on but I can handle it";
    BOOST_LOG_SEV(slg, critical) << "Everything crumbles, shoot me now!";
}

也可如下使用:

void default_severity()
{
    // The default severity can be specified in constructor.
    src::severity_logger< severity_level > error_lg(keywords::severity = error);

    BOOST_LOG(error_lg) << "An error level log record (by default)";

    // The explicitly specified level overrides the default
    BOOST_LOG_SEV(error_lg, warning) << "A warning level log record (overrode the default)";
}

不使用宏的情况:

void manual_logging()
{
    src::severity_logger< severity_level > slg;

    logging::record rec = slg.open_record(keywords::severity = normal);
    if (rec)
    {
        logging::record_ostream strm(rec);
        strm << "A regular message";
        strm.flush();
        slg.push_record(boost::move(rec));
    }
}

logger配合channel

相关的类共有channel_loggerchannel_logger_mtwchannel_loggerwchannel_logger_mt4类
这4个类都有Channel属性
这个类可用来区分不同的log
示例代码:

class network_connection
{
    src::channel_logger< > m_net, m_stat;
    logging::attribute_set::iterator m_net_remote_addr, m_stat_remote_addr;

public:
    network_connection() :
        // We can dump network-related messages through this logger
        // and be able to filter them later
        m_net(keywords::channel = "net"),
        // We also can separate statistic records in a different channel
        // in order to route them to a different sink
        m_stat(keywords::channel = "stat")
    {
    }

    void on_connected(std::string const& remote_addr)
    {
        // Add the remote address to both channels
        attrs::constant< std::string > addr(remote_addr);
        m_net_remote_addr = m_net.add_attribute("RemoteAddress", addr).first;
        m_stat_remote_addr = m_stat.add_attribute("RemoteAddress", addr).first;

        // Put message to the "net" channel
        BOOST_LOG(m_net) << "Connection established";
    }

    void on_disconnected()
    {
        // Put message to the "net" channel
        BOOST_LOG(m_net) << "Connection shut down";

        // Remove the attribute with the remote address
        m_net.remove_attribute(m_net_remote_addr);
        m_stat.remove_attribute(m_stat_remote_addr);
    }

    void on_data_received(std::size_t size)
    {
        BOOST_LOG(m_stat) << logging::add_value("ReceivedSize", size) << "Some data received";
    }

    void on_data_sent(std::size_t size)
    {
        BOOST_LOG(m_stat) << logging::add_value("SentSize", size) << "Some data sent";
    }
};

使用宏的简化版本

// Define a global logger
BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS(my_logger, src::channel_logger_mt< >, (keywords::channel = "general"))

class network_connection
{
    std::string m_remote_addr;

public:
    void on_connected(std::string const& remote_addr)
    {
        m_remote_addr = remote_addr;

        // Put message to the "net" channel
        BOOST_LOG_CHANNEL(my_logger::get(), "net")
            << logging::add_value("RemoteAddress", m_remote_addr)
            << "Connection established";
    }

    void on_disconnected()
    {
        // Put message to the "net" channel
        BOOST_LOG_CHANNEL(my_logger::get(), "net")
            << logging::add_value("RemoteAddress", m_remote_addr)
            << "Connection shut down";

        m_remote_addr.clear();
    }

    void on_data_received(std::size_t size)
    {
        BOOST_LOG_CHANNEL(my_logger::get(), "stat")
            << logging::add_value("RemoteAddress", m_remote_addr)
            << logging::add_value("ReceivedSize", size)
            << "Some data received";
    }

    void on_data_sent(std::size_t size)
    {
        BOOST_LOG_CHANNEL(my_logger::get(), "stat")
            << logging::add_value("RemoteAddress", m_remote_addr)
            << logging::add_value("SentSize", size)
            << "Some data sent";
    }
};

logger另有处理异常的版本自定义混合类别的功能

再谈全局logger

使用全局logger,而在namespace内使用logger的原因:

  • c++没有规定namespace的初始化顺序
  • namespace的初始化并不是线程安全的
  • 在头文件的namespace中设定logger十分麻烦,因为还需要一个cpp文件配合
  • namespace内的变量在其内可访问,换句话说,模块B引用模块A,模块B内会创建同名的变量

使用全局logger可避免这些问题。创建全局logger:

BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::severity_logger_mt< >)

如果创建logger时需要传递参数,那么使用如下的宏,宏中的CTOR代表constructor,ARGS代表arguments

BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS(
    my_logger,
    src::severity_channel_logger< >,
    (keywords::severity = error)(keywords::channel = "my_channel"))

如果前两个宏不能满足要求,还有第三个宏

BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT(my_logger, src::severity_logger_mt)
{
    // Do something that needs to be done on logger initialization,
    // e.g. add a stop watch attribute.
    src::severity_logger_mt< > lg;
    lg.add_attribute("StopWatch", attrs::timer());
    // The initializing routine must return the logger instance
    return lg;
}

分开头文件和CPP文件设置全局logger

虽然上一节的宏可以设置全局logger,但在头文件中定义还是会有些麻烦。于是boost.log提供了在头文件和CPP文件中配合使用的宏:
BOOST_LOG_GLOBAL_LOGGER声明logger,类似于前文的BOOST_LOG_INLINE_GLOBAL_LOGGER*
BOOST_LOG_GLOBAL_LOGGER_INIT, BOOST_LOG_GLOBAL_LOGGER_DEFAULT
BOOST_LOG_GLOBAL_LOGGER_CTOR_ARGS使用类似于BOOST_LOG_INLINE_GLOBAL_LOGGER*,只不过要用在CPP文件中

// my_logger.h
// ===========

BOOST_LOG_GLOBAL_LOGGER(my_logger, src::severity_logger_mt)


// my_logger.cpp
// =============

#include "my_logger.h"

BOOST_LOG_GLOBAL_LOGGER_INIT(my_logger, src::severity_logger_mt)
{
    src::severity_logger_mt< > lg;
    lg.add_attribute("StopWatch", attrs::timer());
    return lg;
}

官方简单教程
官方logger高级教程
转自:https://blog.csdn.net/LaineGates/article/details/90137804

posted @ 2022-10-27 16:26  MasonLee  阅读(777)  评论(0编辑  收藏  举报