版权声明:本文为博主原创文章,未经博主允许不得转载。 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分为frontend
和backend
两种:
frontend_sink
前端,上段代码中的 synchronous_sink
- 负责线程同步、filter和format
- 像logger一样支持
set_filter
和reset_filter
,用于设定filter - 像logger一样支持
set_formatter
和reset_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_backend
和wtext_ostream_backend
,可供使用 - 文件流,有
text_file_backend
,借助了Boost.FileSystem和Boost.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);
}