前言
本文的boost log实力代码具有易读时间戳、可选日志级别和自动换行的C++风格日志打印功能,且保证<<操作符的线程安全性。
支持灵活的日志格式打印,日志文件会自动命名,并允许调整日志大小、数量和剩余空间。支持将日志同时输出到终端和多个文件。
目前未找到按模块打印功能,无法通过配置文件静态调整打印设置,也缺少动态调整打印设置的高级功能。
0、log模块应当支持的功能
- 时间戳、TAG、log level等的打印
- 日志打印条目的用户自定义
- 支持输出到终端或(和多个)文件
- 支持滚动写入文件(文件个数、单个文件大小、总文件大小、文件名、压缩等)
- 支持不同模块打印到不同的文件,level过滤和模块过滤
- 支持通过静态文件配置log(有无动态配置log的?)
- 提供log文件静态查看工具
- 支持将log输出到远程
- 支持远程实时查看log、动态调整log level等功能
一、boost安装
https://www.boost.org/
从下面的网站中选择一个合适的boost版本安装
https://www.boost.org/users/download/
大部分的boost库只有头文件:头文件完全由模版和内敛函数组成,不需要.cpp文件。(在使用boost库时只需要把头文件include一下就可以,配置起来很方便。不过引入boost后编译一个只有几行的cpp文件需要数秒的时间???也无所谓了)
但是Boost.Log库不是Header-Only的,需要编译
boostxx.tar.gz解压后的文件接口
boost_1_82_0/ .................boost根目录,$BOOST_ROOT
index.htm ......... www.boost.org 网站的拷贝 (从这里开始看)
boost/ ....所有的boost头文件就在这里,把该文件复制到/usr/include目录下就算安装好了
`` ``
libs/ ............Tests, .cpps, docs, etc., by library
index.html ........boost中所有包含的库(或者从这里开始看)
algorithm/
any/
array/
…more libraries…
status/ .........................Boost-wide test suite
tools/ ...........Utilities, e.g. Boost.Build, quickbook, bcp
more/ ..........................Policy documents, etc.
doc/ ...............忽略它把,不用看
编译boost二进制库
https://www.boost.org/doc/libs/1_86_0/more/getting_started/unix-variants.html 的 5.1 Easy Build and Install
./bootstrap.sh --prefix=path/to/installation/prefix
./b2 install
二、Boost.Log
Boost.Log库非常强大、灵活,这里只给出了满足基本需求的用法,可快速加入代码使用起来。
Boost.Log库包含三个主要的层:数据采集层,处理所收集数据的层和将前两层互连的中心层。
箭头表示日志信息的流向。从左边的应用程序流向右边最终的存储部分。最右边的可以是储存数据、让电脑发出警报或时记录统计信息等。
logger指的是类实例化后的对象,库中提供了多种类型的logger类型。给予函数式编程思想,实例化一个全局的logger对象,这样使用起来非常方便;如果将logger放在class的定义中,则每一个对象内都含有一个自己的logger
属性和属性值
返回当前时间的函数是一个属性,它的值——某一时间点,时属性值。
有三种类型的属性集:
- 全局 (低优先级)
- 线程特定的
- 源特定的(高优先级)
日志核心和过滤器
当一组属性值组合到一起时,日志核心负责过滤掉不被sink记录的内容。日志核心负责第一层过滤,特定的sink负责第二层过滤
sink
当日志记录至少通过一个接收器的过滤时,它被视为可处理的。如果接收器允许格式化输出,日志消息将在此时进行格式化。格式化后的消息和属性值集合会传递给接收日志的接收器。值得注意的是,格式化是针对每个接收器单独进行的,以便它们可以按照各自的特定格式输出日志记录。
如您在上图中所见,接收器分为前端和后端两部分。这样的划分是为了把接收器的通用功能(例如过滤、格式化和线程同步)分离到一个独立的实体(前端)。接收器的前端通常由库提供,用户通常无需重新实现。而后端则是扩展库的一个潜在领域。接收器后端负责实际处理日志记录。可能有将日志存储到文件的接收器,也可能有通过网络发送日志到远程处理节点的接收器,还可能有将日志消息放入工具提示通知的接收器——正如您所命名的那样。库已经提供了一些最常用的接收器后端。除了主要功能,该库还提供了多种辅助工具,例如属性支持、格式化程序和过滤器(以lambda表达式形式),甚至是库初始化的基础助手。
二、Code fragment
急速使用
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
namespace logging = boost::log;
// 可选的,带有log级别过滤的
void init()
{
logging::core::get()->set_filter
(
logging::trivial::severity >= logging::trivial::info
);
}
int main(int, char*[])
{
init();
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;
}
对init做一些扩展, 让日志存入文件
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
namespace logging = boost::log;
namespace src = boost::log::sources;
namespace sinks = boost::log::sinks;
namespace keywords = boost::log::keywords;
void init()
{
logging::add_file_log("sample.log");
logging::core::get()->set_filter
(
logging::trivial::severity >= logging::trivial::info
);
}
对init再加些,让文件及内容可控
// include 同上
void init()
{
logging::add_file_log
(
keywords::file_name = "sample_%N.log", /*< file name pattern >*/
keywords::rotation_size = 10 * 1024 * 1024, /*< rotate files every 10 MiB... >*/
keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0), /*< ...or at midnight >*/
keywords::format = "[%TimeStamp%]: %Message%" /*< log record format >*/
);
logging::core::get()->set_filter
(
logging::trivial::severity >= logging::trivial::info
);
logging::add_common_attributes();
}
int main(int, char*[])
{
init();
logging::add_common_attributes();
using namespace logging::trivial;
src::severity_logger< severity_level > lg;
BOOST_LOG_SEV(lg, trace) << "A trace severity message";
BOOST_LOG_SEV(lg, debug) << "A debug severity message";
BOOST_LOG_SEV(lg, info) << "An informational severity message";
BOOST_LOG_SEV(lg, warning) << "A warning severity message";
BOOST_LOG_SEV(lg, error) << "An error severity message";
BOOST_LOG_SEV(lg, fatal) << "A fatal severity message";
return 0;
}
code example
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream>
#include <thread>
#include <iomanip>
#include <fstream>
#include <boost/core/null_deleter.hpp>
#include <boost/log/attributes/current_thread_id.hpp>
#include <boost/log/attributes/current_process_id.hpp>
#include <boost/log/attributes/current_process_name.hpp>
#include <boost/log/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/sources/logger.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared_object.hpp>
namespace logging = boost::log;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace sinks = boost::log::sinks;
namespace keywords = boost::log::keywords;
namespace attrs = boost::log::attributes;
void my_formatter(logging::record_view const& rec, logging::formatting_ostream& strm)
{
// // Get the LineID attribute value and put it into the stream
// strm << logging::extract< unsigned int >("LineID", rec) << ": ";
// time_t stamp;
// time(&stamp);
// strm << "[%TimeStamp%]";
// // The same for the severity level.
// // The simplified syntax is possible if attribute keywords are used.
// strm << "<" << rec[logging::trivial::severity] << "> ";
// // Finally, put the record message to the stream
// strm << rec[expr::smessage];
}
void init2()
{
boost::shared_ptr<logging::core> core = logging::core::get();
core->set_filter(logging::trivial::severity >= logging::trivial::debug);
core->add_global_attribute("LineID", attrs::counter<unsigned int>(1));
core->add_global_attribute("TimeStamp", attrs::local_clock());
core->add_global_attribute("Process", attrs::current_process_id());
core->add_global_attribute("Process", attrs::current_process_name());
core->add_global_attribute("ThreadID", attrs::current_thread_id());
typedef sinks::synchronous_sink< sinks::text_ostream_backend > text_stream;
boost::shared_ptr< text_stream > sink_cout_backend = boost::make_shared< text_stream >();
boost::shared_ptr<std::ostream> stream(&std::cout, boost::null_deleter());
sink_cout_backend->locked_backend()->add_stream(stream);
// sink_cout_backend->locked_backend()->add_stream(
// boost::make_shared< std::ofstream >("sample1.log"));
// sink_cout_backend->set_formatter(
// expr::format("%1%: <%2%> %3%")
// % expr::attr<unsigned int>("ThreadID")
// % logging::trivial::severity
// % expr::smessage
// );
// sink_cout_backend->set_formatter
// (
// expr::stream
// // line id will be written in hex, 8-digits, zero-filled
// << std::hex << std::setw(8) << std::setfill('0') << expr::attr< unsigned int >("LineID")
// << ": <" << logging::trivial::severity
// << "> " << expr::smessage
// );
// sink_cout_backend->set_formatter(&my_formatter);
sink_cout_backend->set_formatter(
expr::stream
<< "["
<< expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S.%f")
<< "]"
<< " <" << logging::trivial::severity
<< "> "
<< expr::smessage
);
// Register the sink in the logging core
core->add_sink(sink_cout_backend);
// Construct the sink
typedef sinks::synchronous_sink< sinks::text_file_backend > text_file;
boost::shared_ptr< sinks::text_file_backend > file_backend =
boost::make_shared< sinks::text_file_backend >(
// keywords::file_name = "logs/file_%Y-%m-%d_%N.log", /*< file name pattern >*/
keywords::file_name = "logs/sample_%N.log",
keywords::open_mode = std::ios_base::app,
keywords::rotation_size = 10 * 1024 * 1024, /*< rotate files every 10 MiB... >*/
keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0) /*< ...or at midnight >*/
);
boost::shared_ptr<text_file> sink_file_backend(new text_file(file_backend));
sink_file_backend->set_formatter(
expr::stream
<< "["
<< expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S.%f")
<< "]"
<< " <" << logging::trivial::severity
<< "> "
<< expr::smessage
);
sink_file_backend->locked_backend()->set_file_collector(sinks::file::make_collector(
keywords::target = "logs",
keywords::max_size = 500 * 1024 * 1024,
keywords::max_files = 5
));
core->add_sink(sink_file_backend);
logging::add_common_attributes();
}
int main(int, char*[])
{
init2();
src::severity_logger_mt<logging::trivial::severity_level> lg2;
BOOST_LOG_SEV(lg2, logging::trivial::info) << "\n---------------------log start------------------";
for (size_t i = 0; i < 100; i++)
{
BOOST_LOG_SEV(lg2, logging::trivial::fatal) << "times:" << i;
BOOST_LOG_SEV(lg2, logging::trivial::trace) << "a trace severity message" << "tracedone1";
BOOST_LOG_SEV(lg2, logging::trivial::debug) << "a debug severity message" << "debugdone2";
BOOST_LOG_SEV(lg2, logging::trivial::info) << "a info severity message2222222" << "infodone3";
BOOST_LOG_SEV(lg2, logging::trivial::warning) << "a warning severity message" << "warningdone";
BOOST_LOG_SEV(lg2, logging::trivial::error) << "a error severity message222222222" << "errordone";
BOOST_LOG_SEV(lg2, logging::trivial::fatal) << "a k款死组fatal severity message" << "fataldone";
char buf[] = "lsjdljflsdjf";
BOOST_LOG_SEV(lg2, logging::trivial::debug) << buf; /* code */
}
return 0;
}
g++ -std=c++11 -DBOOST_LOG_DYN_LINK logger.cpp -lboost_log -lpthread -lboost_log_setup -lboost_thread -lboost_system -o test
BOOST_LOG_DYN_LINK宏影响所有使用Boost.Log库的代码,定义了改该宏,log库作为动态库,否则认为是静态库