boost.log 教程:sink

直接使用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说明

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
org.apache.flume.EventDeliveryException: Failed to send events at org.apache.flume.sink.AbstractRpcSink.process(AbstractRpcSink.java:389) at org.apache.flume.sink.DefaultSinkProcessor.process(DefaultSinkProcessor.java:67) at org.apache.flume.SinkRunner$PollingRunner.run(SinkRunner.java:145) at java.lang.Thread.run(Thread.java:748) Caused by: org.apache.flume.FlumeException: NettyAvroRpcClient { host: localhost, port: 44444 }: RPC connection error at org.apache.flume.api.NettyAvroRpcClient.connect(NettyAvroRpcClient.java:181) at org.apache.flume.api.NettyAvroRpcClient.connect(NettyAvroRpcClient.java:120) at org.apache.flume.api.NettyAvroRpcClient.configure(NettyAvroRpcClient.java:638) at org.apache.flume.api.RpcClientFactory.getInstance(RpcClientFactory.java:90) at org.apache.flume.sink.AvroSink.initializeRpcClient(AvroSink.java:127) at org.apache.flume.sink.AbstractRpcSink.createConnection(AbstractRpcSink.java:210) at org.apache.flume.sink.AbstractRpcSink.verifyConnection(AbstractRpcSink.java:270) at org.apache.flume.sink.AbstractRpcSink.process(AbstractRpcSink.java:346) ... 3 more Caused by: java.io.IOException: Error connecting to localhost/127.0.0.1:44444 at org.apache.avro.ipc.NettyTransceiver.getChannel(NettyTransceiver.java:261) at org.apache.avro.ipc.NettyTransceiver.<init>(NettyTransceiver.java:203) at org.apache.avro.ipc.NettyTransceiver.<init>(NettyTransceiver.java:152) at org.apache.flume.api.NettyAvroRpcClient.connect(NettyAvroRpcClient.java:167) ... 10 more Caused by: java.net.ConnectException: 拒绝连接: localhost/127.0.0.1:44444 at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717) at org.jboss.netty.channel.socket.nio.NioClientBoss.connect(NioClientBoss.java:152) at org.jboss.netty.channel.socket.nio.NioClientBoss.processSelectedKeys(NioClientBoss.java:105) at org.jboss.netty.channel.socket.nio.NioClientBoss.process(NioClientBoss.java:79) at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:318) at org.jboss.netty.channel.socket.nio.NioClientBoss.run(NioClientBoss.java:42) at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108) at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ... 1 more
06-11

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值