boost.log 教程:sink

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LaineGates/article/details/90141210

直接使用trivial logging 很多时候无法满足需求,比如有时想定义些特定的标签,写到特定的文件,这时就要用到sink。

sink应该只在应用程序的开始设置

如果没有设定sink,系统会生成默认的,是输出到console,但如果用户自己指定了,那么默认的sink不再生效

使用file sink

简单示例:

void init()
{
    logging::add_file_log("sample.log");
    logging::core::get()->set_filter
    (
        logging::trivial::severity >= logging::trivial::info  // 借助Boost.Phoenix,函数式编程
    );
}

add_file_log提供了简单的参数设置功能

    logging::add_file_log
    (
        keywords::file_name = "sample_%N.log",                                        
        keywords::rotation_size = 10 * 1024 * 1024,                                   
        keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0),
        keywords::format = "[%TimeStamp%]: %Message%"                                 
    );

更加详细的说明
add_file_log函数大致等于如下函数

void init()
{
    // Construct the sink
    typedef sinks::synchronous_sink< sinks::text_ostream_backend > text_sink;
    boost::shared_ptr< text_sink > sink = boost::make_shared< text_sink >();

    // Add a stream to write log to
    sink->locked_backend()->add_stream(
        boost::make_shared< std::ofstream >("sample.log"));

    // Register the sink in the logging core
    logging::core::get()->add_sink(sink);
}

前端后和后端的sink

sink分为frontendbackend两种:

frontend_sink

前端,上段代码中的 synchronous_sink

  • 负责线程同步、filter和format
  • 像logger一样支持set_filterreset_filter,用于设定filter
  • 像logger一样支持set_formatterreset_formatter,也可使用lambda表达式
  • 像logger一样支持set_exception_handler,且默认异常无返回值和可多线程调用
  • logging core调用sink的will_consume函数后,sink开始工作
  • 线程安全性
    • synchronous*开头,如synchronous_sink是线程安全的
    • unlocked_*开头,如unlocked_sink是不保证线程安全的,这种sink假定不需要或backend sink会做
    • asynchronous_sink是异步的sink,这个会使用消息队列,消息队列意味着应用异常时信息不一定被全输出,具体参见网页
    • frontend_sink详细说明

backend_sink

后端

  • 执行具体的操作,如保存到文件、发送到网络等
  • 提供auto_flush,用于设置实时将字符输出,比如写入文件
  • 一个backend_sink可以有多个stream输出,但输出的内容是一样的,需不同输出就要不同的sink
  • 字符流,有text_ostream_backendwtext_ostream_backend,可供使用
  • 文件流,有text_file_backend,借助了Boost.FileSystemBoost.DateTime,相比于用text_ostream_backend输出到文件,有如下优势:
    • 可设置输出文件大小及时间,用来更新文件(即新建一个文件,原文称rotation
    • 灵活的文件重命名功能
    • 将ratotation出的新文件输出到特定目录,而且启动时调用scan_for_files()根据当前rotation设置扫描已经有log文件
    • 删除旧文件以节省硬盘空间
    • 设置文件开头set_open_handler及结尾set_close_handler,如设置XML的首尾标签
    • 支持auto_flush功能
    • 示例见后文
    • 详情见网页
  • 多文件流
    • 可使用一个文件流输出到多个文件,文件的区分依据动态的属性
    • 没有文件关闭功能,也无法确定当前文件是否要关闭,即rotation功能无效
  • 网络IPC流,text_ipc_message_queue_backend
  • 系统消息流 syslog_backend
  • windows调试信息流 debug_output_backend 和 wdebug_output_backend,比较复杂,不建议使用
  • windows信息流 simple_event_log_backend比较复杂,不建议使用
  • backend_sink详细说明

字符流示例

通过sink将信息输出到std::cout和文件

void init_logging()
{
    boost::shared_ptr< logging::core > core = logging::core::get();
    // Create a backend and attach a couple of streams to it
    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())); //输出到std::cout
    backend->add_stream(
        boost::shared_ptr< std::ostream >(new std::ofstream("sample.log")));  //输出到文件

    // Enable auto-flushing after each log record written
    backend->auto_flush(true);

    // Wrap it into the frontend and register in the core.
    // The backend requires synchronization in the frontend.
    typedef sinks::synchronous_sink< sinks::text_ostream_backend > sink_t;
    boost::shared_ptr< sink_t > sink(new sink_t(backend));
    core->add_sink(sink);
}

通过add_stream(), backedn可添置多个输出流

通过locked_backend(),保证sink被线程锁定

文件流示例

使用文件流backend

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

    boost::shared_ptr< sinks::text_file_backend > backend =
        boost::make_shared< sinks::text_file_backend >(
            keywords::file_name = "file.log",  /*文件名*/ 
            keywords::target_file_name = "file_%5N.log", /*rotation后的文件名*/   
            keywords::rotation_size = 5 * 1024 * 1024,   /*输出文件大小,并不完全精确*/                    
            keywords::time_based_rotation = sinks::file::rotation_at_time_point(12, 0, 0)  /*rotation时间点*/
            // keywords::enable_final_rotation = false /*此参数可取消rotation功能*/
        );

    // Wrap it into the frontend and register in the core.
    // The backend requires synchronization in the frontend.
    typedef sinks::synchronous_sink< sinks::text_file_backend > sink_t;
    boost::shared_ptr< sink_t > sink(new sink_t(backend));

    core->add_sink(sink);
}

设置文件流首尾

// Complete file sink type
typedef sinks::synchronous_sink< sinks::text_file_backend > file_sink;

void write_header(sinks::text_file_backend::stream_type& file)
{
    file << "<?xml version=\"1.0\"?>\n<log>\n";
}

void write_footer(sinks::text_file_backend::stream_type& file)
{
    file << "</log>\n";
}

void init_logging()
{
    // Create a text file sink
    boost::shared_ptr< file_sink > sink(new file_sink(
        keywords::file_name = "%Y%m%d_%H%M%S_%5N.xml",  1
        keywords::rotation_size = 16384                 2
    ));

    sink->set_formatter
    (
        expr::format("\t<record id=\"%1%\" timestamp=\"%2%\">%3%</record>")
            % expr::attr< unsigned int >("RecordID")
            % expr::attr< boost::posix_time::ptime >("TimeStamp")
            % expr::xml_decor[ expr::stream << expr::smessage ]            3
    );

    // Set header and footer writing functors
    sink->locked_backend()->set_open_handler(&write_header);
    sink->locked_backend()->set_close_handler(&write_footer);

    sink->locked_backend()->scan_for_files();  // 根据sink设置先扫描已有的rotation文件
    // Add the sink to the core
    logging::core::get()->add_sink(sink);
}

多文件流示例

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

    boost::shared_ptr< sinks::text_multifile_backend > backend =
        boost::make_shared< sinks::text_multifile_backend >();

    // Set up the file naming pattern
    backend->set_file_name_composer
    (
        sinks::file::as_file_name_composer(expr::stream << "logs/" << expr::attr< std::string >("RequestID") << ".log")
    );

    // Wrap it into the frontend and register in the core.
    // The backend requires synchronization in the frontend.
    typedef sinks::synchronous_sink< sinks::text_multifile_backend > sink_t;
    boost::shared_ptr< sink_t > sink(new sink_t(backend));

    // Set the formatter
    sink->set_formatter
    (
        expr::stream
            << "[RequestID: " << expr::attr< std::string >("RequestID")
            << "] " << expr::smessage
    );

    core->add_sink(sink);
}

参考
官方简单说明
官方frontend_sink说明
官方backend_sink说明

猜你喜欢

转载自blog.csdn.net/LaineGates/article/details/90141210