boost.log教程:core facilities

Logging records

logging record中的所有信息,包括message text,都会被filters, formatters 和 sinks处理。
logging record特性:

  • 不能复制,只能被移动boost::move()。它由logging core在filter之后创建,此时内容为空,随后attribute value会由attribute生成并添加到log record
  • logging record可在formatting和sink时继续添加attributes
  • 多线程环境中,logging record与创建它的线程绑定,所以logging record不能在线程中移动。

读取这些信息的方式有几种:

通过 logging::visitlogging::value_ref

更详细参见网页

enum severity_level { ... };
std::ostream& operator<< (std::ostream& strm, severity_level level);

struct print_visitor
{
    typedef void result_type;
    result_type operator() (severity_level level) const
    {
        std::cout << level << std::endl;
    };
};

// Prints severity level through visitation API
void print_severity_visitation(logging::record const& rec)
{
    logging::visit< severity_level >("Severity", rec, print_visitor());
}

// Prints severity level through extraction API
void print_severity_extraction(logging::record const& rec)
{
    logging::value_ref< severity_level > level = logging::extract< severity_level >("Severity", rec);
    std::cout << level << std::endl;
}

通过 attribute_values访问所有属性

更详细参见网页

// Prints severity level by searching the attribute values
void print_severity_lookup(logging::record const& rec)
{
    logging::attribute_value_set const& values = rec.attribute_values();
    logging::attribute_value_set::const_iterator it = values.find("Severity");
    if (it != values.end())
    {
        logging::attribute_value const& value = it->second;

        // A single attribute value can also be visited or extracted
        std::cout << value.extract< severity_level >() << std::endl;
    }
}

直接通过下标方式访问

BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level)

// Prints severity level by using the subscript operator
void print_severity_subscript(logging::record const& rec)
{
    // Use the attribute keyword to communicate the name and type of the value
    logging::value_ref< severity_level, tag::severity > level = rec[severity];
    std::cout << level << std::endl;
}

Record view

与logging record相似, record用来填充信息,record view用来后续处理:

  • record view不可变,可防止formatter及sink修改它
  • record view可复制,因为内容不可改,使用浅复制成本很低

boost会自动在lock函数被调用时,为record创建record view:

  • record view不会绑定到线程
  • record 会在lock结束后变空值,因为record只被处理一次

Logging core

logging core是库的核心,提供:

  • 维护全局和各线程的attribute sets
  • 处理log record的全局过滤
  • 应用sink的filter在sink间传递log record
  • 提供全局的exception handler
  • 提供全局的log record输入口
  • 提供flush强制输出

访问方式

boost::shared_ptr< logging::core > core = logging::core::get();

Attribute sets

添加/删除全局属性add_global_attributeremove_global_attribute
添加/删除线程属性add_thread_attributeremove_thread_attribute

void foo()
{
    boost::shared_ptr< logging::core > core = logging::core::get();

    // Add a global attribute
	// 返回值第一个参数是其被添加后的索引,bool代表是否添加成功
    std::pair< logging::attribute_set::iterator, bool > res =
        core->add_global_attribute("LineID", attrs::counter< unsigned int >());
    // Do something ...
    // Remove the added attribute
    core->remove_global_attribute(res.first);
}

logging::core的所有方法都是线程安全的,但索引不能保证线程安全
获取/设置全局属性get_global_attributesset_global_attributes
获取/设置线程属性get_thread_attributesset_thread_attributes


Global filtering

filter读入一组参数,返回此record是否通过
设置/清除filter的函数set_filter/ reset_filter,filter没有设置,相当于所有log record可通过
通过set_logging_enabled,可设置filter是否生效,比较设置filter更高效。


Sink management

添加/删除sink的函数,add_sinkremove_sink。添加的sink会保存到logging core中,但sink的执行顺序是不确定的。

void foo()
{
    boost::shared_ptr< logging::core > core = logging::core::get();

    // Set a sink that will write log records to the console
    boost::shared_ptr< sinks::text_ostream_backend > backend =
        boost::make_shared< sinks::text_ostream_backend >();
    backend->add_stream(
        boost::shared_ptr< std::ostream >(&std::clog, boost::null_deleter()));

    typedef sinks::unlocked_sink< sinks::text_ostream_backend > sink_t;
    boost::shared_ptr< sink_t > sink = boost::make_shared< sink_t >(backend);
    core->add_sink(sink);

    // ...

    // Remove the sink
    core->remove_sink(sink);
}

sink的详细说明见frontendbackend


Exception handling

添加异常处理类,通过set_exception_handler设置,其参数是无参数函数,在catch语句中被调用。
logging core中的异常处理类只应该处理通用错误。
Logging sinks 和 sources 可做更细致的异常处理,参见
sink异常处理source异常处理

struct my_handler
{
    typedef void result_type;

    void operator() (std::runtime_error const& e) const
    {
        std::cout << "std::runtime_error: " << e.what() << std::endl;
    }
    void operator() (std::logic_error const& e) const
    {
        std::cout << "std::logic_error: " << e.what() << std::endl;
        throw;
    }
};

void init_exception_handler()
{
    // Setup a global exception handler that will call my_handler::operator()
    // for the specified exception types
    logging::core::get()->set_exception_handler(logging::make_exception_handler<
        std::runtime_error,  /*处理的错误类型*/
        std::logic_error
    >(my_handler()));
}

Feeding log records

logging core最重要的功能之一就是创建和推送log record,实现函数分别为open_recordpush_record.

  • open_record收集global, thread-specific 和 source-specific的属性,判断是否会被filter掉,如果没有被filter掉(至少有一个sink接收这个record),函数会返回一个log record对象
  • push_record在由open_record获得的record对象填写完内容后调用。之后record view对象会从record对象中生成,并传给接收它的多个sink,这个过程中会发生formatting及保存到文件等操作,视情况而不同。随后record对象被销毁。
void logging_function(logging::attribute_set const& attrs)
{
    boost::shared_ptr< logging::core > core = logging::core::get();

    // Attempt to open a log record
    logging::record rec = core->open_record(attrs);
    if (rec)
    {
        // Ok, the record is accepted. Compose the message now.
        logging::record_ostream strm(rec);
        strm << "Hello, World!";
        strm.flush();

        // Deliver the record to the sinks.
        core->push_record(boost::move(rec));
    }
}

官方说明

上一篇:flume的Sink和channel


下一篇:Flink从socket读取数据sink到redis