1.目标

程序日志输出改进目标:

1. 用颜色区分错误和警告

2. 日志文件中用"warning"文本代替数字表示severity,便于日志中搜索

3. 合并log_setting.ini配置文件(到程序json配置文件,不使用init_from_stream)

4. 可同时输出到console和文件

资料未整理完,以后再补充对程序的说明。

2.实现

log.h


enum SeverityLevel {SL_TRACE = 0,SL_DEBUG,SL_INFO,SL_WARNING,SL_ERROR,SL_CRITICAL
};class Log {
public:static void init_log();
private:static void init_logfile();static void init_console();
};boost::log::sources::severity_logger<SeverityLevel>* get_glog();

log.cpp

#include "log.h"#include<ios>
#include <boost/ref.hpp>
#include <boost/bind.hpp>
#include <boost/log/core.hpp>
#include <boost/log/common.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/core/record.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/core/null_deleter.hpp>namespace logging = boost::log;
namespace attrs = boost::log::attributes;
namespace src = boost::log::sources;
namespace sinks = boost::log::sinks;
namespace expr = boost::log::expressions;
namespace keywords = boost::log::keywords;/* Define place holder attributes */
BOOST_LOG_ATTRIBUTE_KEYWORD(line_id, "LineID", unsigned int)
BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)
//BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", logging::trivial::severity_level)
//BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", logging::trivial::severity )
#include <boost/phoenix.hpp>
BOOST_LOG_ATTRIBUTE_KEYWORD(process_id, "ProcessID", attrs::current_process_id::value_type )
BOOST_LOG_ATTRIBUTE_KEYWORD(thread_id, "ThreadID", attrs::current_thread_id::value_type )// Get Process native ID
attrs::current_process_id::value_type::native_type get_native_process_id(logging::value_ref<attrs::current_process_id::value_type,tag::process_id> const& pid) {if (pid)return pid->native_id();return 0;
}// Get Thread native ID
attrs::current_thread_id::value_type::native_type get_native_thread_id(logging::value_ref<attrs::current_thread_id::value_type,tag::thread_id> const& tid) {if (tid)return tid->native_id();return 0;
}typedef SeverityLevel severity_level;
const char *get_severity_tag(severity_level level) {static const char* strings[] = {"trace","debug","info","waring","error","critical"};return static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings) ? strings[level] : std::to_string(level).c_str();
}void coloring_formatter(logging::record_view const& rec, logging::formatting_ostream& strm) {logging::value_ref< severity_level > level = logging::extract< severity_level >("Severity", rec);switch(level.get()) {case crush::common::SL_TRACE:case crush::common::SL_DEBUG:case crush::common::SL_INFO:strm << "\033[32m";break;case  crush::common::SL_WARNING:strm << "\033[33m";break;case crush::common::SL_ERROR:case crush::common::SL_CRITICAL:strm << "\033[31m";break;default:break;}strm << logging::extract< unsigned int >("LineID", rec) << "|";auto date_time_formatter = expr::stream << expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S.%f");date_time_formatter(rec, strm);strm <<"|";strm<< std::dec<< logging::extract< attrs::current_process_id::value_type  >("ProcessID", rec);strm << "|";strm<< std::dec<< logging::extract< attrs::current_thread_id::value_type  >("ThreadID", rec);strm << "|";strm<< get_severity_tag(level.get());strm<< "|";strm<<"--";strm << rec[logging::expressions::smessage];// Restore the default colorstrm << "\033[0m";
}struct severity_tag;
logging::formatting_ostream& operator<<
(logging::formatting_ostream& strm,logging::to_log_manip< severity_level, severity_tag > const& manip
) {severity_level level = manip.get();strm << get_severity_tag(level);return strm;
}BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(glog, boost::log::sources::severity_logger<SeverityLevel>);void Log::init_console() {typedef sinks::synchronous_sink< sinks::text_ostream_backend > text_sink;boost::shared_ptr< text_sink > sink = boost::make_shared< text_sink >();boost::shared_ptr< std::ostream > stream(&std::clog, boost::null_deleter());sink->locked_backend()->add_stream(stream);sink->set_formatter(&coloring_formatter);logging::core::get()->add_sink(sink);
}void Log::init_logfile() {logging::add_file_log(keywords::file_name = "%Y-%m-%d_%5N.log",keywords::rotation_size = 10 * 1024 * 1024,keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0),keywords::auto_flush = true,keywords::open_mode =  std::ios::out | std::ios::app,keywords::format =(expr::stream<< expr::attr< unsigned int >("LineID")<<"|"<< expr::format_date_time(expr::attr< boost::posix_time::ptime >("TimeStamp"), "%Y-%m-%d, %H:%M:%S.%f") << "|"<< boost::phoenix::bind(&get_native_process_id, process_id.or_none()) << ":"<< boost::phoenix::bind(&get_native_thread_id, thread_id.or_none()) << "|"<< "[" << expr::attr< severity_level, severity_tag >("Severity")<< "] " << expr::smessage));
}
void Log::init_log() {logging::core::get()->set_filter([](const logging::attribute_value_set& attr_set) {return attr_set["Severity"].extract<severity_level>() >= SL_WARNING;});init_logfile();init_console();logging::add_common_attributes();
}boost::log::sources::severity_logger<SeverityLevel>* get_glog() {return &(glog::get());
}

3.使用

#include "log.h"void test_log() {Log::init();BOOST_LOG_SEV(*(crush::common::get_glog()), SL_TRACE) << "A trace severity message";BOOST_LOG_SEV(*(crush::common::get_glog()), SL_DEBUG) << "A debug severity message";BOOST_LOG_SEV(*(crush::common::get_glog()), SL_INFO) << "An informational severity message";BOOST_LOG_SEV(*(crush::common::get_glog()), SL_WARNING) << "A warning severity message";BOOST_LOG_SEV(*(crush::common::get_glog()), SL_ERROR) << "An error severity message";BOOST_LOG_SEV(*(crush::common::get_glog()), SL_CRITICAL) << "A fatal severity message";LOG_TRACE<<"this a trace";LOG_ERROR<<"this a error";return;
}

4.资料

4.1Howto

How to add color coding to boost::log console output?
https://stackoverflow.com/questions/38309479/how-to-add-color-coding-to-boostlog-console-output

A simple, customized logger, based on Boost.Log v2
http://gernotklingler.com/blog/simple-customized-logger-based-boost-log-v2/

how to print ProcessID and ThreadID in dec-format with boost.log
https://stackoverflow.com/questions/27597196/how-to-print-processid-and-threadid-in-dec-format-with-boost-log

how to customize “TimeStamp” format of Boost.Log
https://stackoverflow.com/questions/5947018/how-to-customize-timestamp-format-of-boost-log

How to use boost::log::expressions::format_date_time in a custom formatting function?
https://stackoverflow.com/questions/24287547/how-to-use-boostlogexpressionsformat-date-time-in-a-custom-formatting-func

boost log, why not print threadid and processid
https://stackoverflow.com/questions/46337337/boost-log-why-not-print-threadid-and-processid

Boost set_filter is not working
https://stackoverflow.com/questions/29707017/boost-set-filter-is-not-working

boost.log : using c++11 lambda expression to filter severity level
https://stackoverflow.com/questions/32399608/boost-log-using-c11-lambda-expression-to-filter-severity-level

Boost log and severity / local attributes

https://stackoverflow.com/questions/35895199/boost-log-and-severity-local-attributes

支持__FILE__,__LINE__

boost.log要点笔记

https://www.cnblogs.com/liaocheng/p/4222885.html

4.2官方文档

Setting up sinks
https://www.boost.org/doc/libs/1_67_0/libs/log/doc/html/log/tutorial/sinks.html

Adding more information to log: Attributes
https://www.boost.org/doc/libs/1_67_0/libs/log/doc/html/log/tutorial/attributes.html
https://www.boost.org/doc/libs/1_67_0/libs/log/doc/html/log/detailed/expressions.html#log.detailed.expressions.attr

Sink backends
https://www.boost.org/doc/libs/master/libs/log/doc/html/log/detailed/sink_backends.html
Filters
http://boost-log.sourceforge.net/libs/log1/doc/html/log/detailed/filters.html

Log record formatting

https://www.boost.org/doc/libs/1_67_0/libs/log/doc/html/log/tutorial/formatters.html

logging::init_from_settings,

https://www.boost.org/doc/libs/1_67_0/libs/log/doc/html/log/detailed/utilities.html#log.detailed.utilities.setup.filter_formatter

5.经验

5.1使用logging::formatter_factory

#日志输出格式
Format=[%TimeStamp% PID:%ProcessID% ThreadID:%ThreadID%] [%Severity%] %MyScopes% %Message%"

注意%MyScopes%

struct ScopeListFormatter {typedef attrs::named_scope::value_type scope_stack;explicit ScopeListFormatter(logging::attribute_name const &name) :name_(name) {}/// @notes///  rec.attribute_values()是attrs::named_scope::value_type吗?/// 代码的运行效果是:%MyScopes%处输出有颜色的当前时间. ///  ? 无法控制日志输出的其它项,如%Message%void operator()(logging::record_view const &rec, logging::formatting_ostream &strm) const {// We need to acquire the attribute value from the log recordlogging::value_ref< severity_level > level = logging::extract< severity_level >("Severity", rec);if (level==SL_ERROR)strm<< "\033[31m";logging::visit<scope_stack>(name_,rec.attribute_values(),boost::bind(&ScopeListFormatter::format, _1, boost::ref(strm)));strm<<"\033[0m";}private://! This is where our custom formatting takes placestatic void format(scope_stack const &scopes, logging::formatting_ostream &strm) {using namespace std::chrono;system_clock::time_point time_now = system_clock::now();microseconds duration_in_mics = duration_cast<microseconds>(time_now.time_since_epoch());strm << "[" << duration_in_mics.count() << "]";scope_stack::const_iterator it = scopes.begin(), end = scopes.end();/// @notes /// .scopes是空的,怎么才能加入元素?/// . it->scope_name,it->file_name的含义和使用? for (; it != end; ++it) {strm << "\t" << it->scope_name << " [" << it->file_name << ":" << it->line << "]\n";}}private:logging::attribute_name name_;
};class MyScopesFormatterFactory :public logging::formatter_factory<char> {
public:
//
//     * This function creates a formatter for the MyScopes attribute.
//     * It effectively associates the attribute with the scope_list_formatter class
//formatter_type create_formatter(logging::attribute_name const &attr_name, args_map const &args) {return formatter_type(ScopeListFormatter(attr_name));}
};

调用代码:

logging::register_formatter_factory("MyScopes", boost::make_shared<MyScopesFormatterFactory>());
logging::core::get()->add_global_attribute("MyScopes", attrs::named_scope());

5.2使用logging::init_from_stream

[Core]
#是否开启Log
DisableLogging=false[Sinks.TextFileSettings]
#输出到哪,支持TextFile Console
Destination=Console#过滤日志等级
#trace = 0, debug = 1, info = 2, warning = 3, error = 4, critical = 5
Filter="%Severity% >= 0"#输出的文件名
FileName="%Y-%m-%d_%5N.log"#单个log文件大小
RotationSize=204800000#产生新的log文件时间点
RotationTimePoint="00:00:00"#是否开启追加
Append=true#是否自动刷新
AutoFlush=true#日志输出格式
Format="[%TimeStamp% PID:%ProcessID% ThreadID:%ThreadID%] [%Severity%] %MyScopes% %Message%"#是否开启异步
Asynchronous=false

使用代码:

std::ifstream settings(filepath);
logging::init_from_stream(settings);

5.3自定义severity

severity_level类型
不同的severity_level定义,coloring_formatter中level的内容不同.

typedef int severity_level; ///level有内容,正确
typedef SeverityLevel severity_level; ///< level.get(),断言抛出异常.void coloring_formatter(logging::record_view const& rec, logging::formatting_ostream& strm) {logging::value_ref< severity_level > level = logging::extract< severity_level >("Severity", rec);switch(level.get()) {

异常的原因是未指定 SeverityLevel参数

修改

boost::log::sources::severity_logger<>* get_glog();
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(glog, boost::log::sources::severity_logger<>);   

为:

boost::log::sources::severity_logger<SeverityLevel>* get_glog();
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(glog, boost::log::sources::severity_logger<SeverityLevel>);      

5.4 logging::formatter

console的格式化输出的另外一种方式.

void Log::init_console() {typedef sinks::synchronous_sink< sinks::text_ostream_backend > text_sink;boost::shared_ptr< text_sink > sink = boost::make_shared< text_sink >();boost::shared_ptr< std::ostream > stream(&std::clog, boost::null_deleter());sink->locked_backend()->add_stream(stream);//   sink->set_formatter(&coloring_formatter);/// @note 是phoneix函数对象?logging::formatter formatter = expr::stream<< std::setw(7) << std::setfill('0') << line_id << std::setfill(' ') << " | "<< expr::format_date_time(timestamp, "%Y-%m-%d, %H:%M:%S.%f") << " "<< "[" << logging::trivial::severity << "]"<< " - " << expr::smessage;sink->set_formatter(formatter)logging::core::get()->add_sink(sink);
}

boost 的函数式编程库 Phoenix入门学习
https://blog.csdn.net/doon/article/details/9119601

5.5 BOOST_LOG_ATTRIBUTE_KEYWORD

查看宏展开代码
创建test2.cpp,内容如下:

#include <boost/log/attributes.hpp>
#include <boost/log/expressions.hpp>BOOST_LOG_ATTRIBUTE_KEYWORD(line_id, "LineID", unsigned int)
BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)

编译:

  g++ -std=c++11 -g -E -P  -c ./test2.cpp > b.txt

查看b.txt内容:
line_id,timestamp展开后的定义:

namespace tag {
struct line_id : public ::boost::log::expressions::keyword_descriptor {typedef unsigned int value_type;static ::boost::log::attribute_name get_name() {return ::boost::log::attribute_name("LineID");}
};
}
typedef ::boost::log::expressions::attribute_keyword< tag::line_id > line_id_type;const line_id_type line_id = {};namespace tag {
struct timestamp : public ::boost::log::expressions::keyword_descriptor {typedef boost::posix_time::ptime value_type;static ::boost::log::attribute_name get_name() {return ::boost::log::attribute_name("TimeStamp");}
};
} typedef ::boost::log::expressions::attribute_keyword< tag::timestamp > timestamp_type;
const timestamp_type timestamp = {};

相关宏:
文件:/usr/local/include/boost/log/expressions/keyword.hpp

#define BOOST_LOG_ATTRIBUTE_KEYWORD(keyword_, name_, value_type_)\BOOST_LOG_ATTRIBUTE_KEYWORD_IMPL(keyword_, name_, value_type_, tag)#define BOOST_LOG_ATTRIBUTE_KEYWORD_IMPL(keyword_, name_, value_type_, tag_ns_)\BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE_IMPL(keyword_, name_, value_type_, tag_ns_)\const BOOST_PP_CAT(keyword_, _type) keyword_ = {};    

默认属性:

namespace boost {
namespace log { inline namespace v2s_mt_posix {
namespace aux {
namespace default_attribute_names {attribute_name severity();attribute_name channel();attribute_name message();attribute_name line_id();attribute_name timestamp();attribute_name process_id();attribute_name thread_id();
}
}
}}
}

5.6 keywords::format指定

void Log::init_logfile() {logging::add_file_log(keywords::file_name = "%Y-%m-%d_%5N.log",keywords::rotation_size = 10 * 1024 * 1024,keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0),keywords::auto_flush = true,keywords::open_mode =  std::ios::out | std::ios::app,/// @notes 属性名称方式//       keywords::format = "[%TimeStamp% PID:%ProcessID% ThreadID:%ThreadID%] [%Severity%]  %Message%"// @question 以下是lambda还是phoneix?keywords::format =(expr::stream<< expr::attr< unsigned int >("LineID")<<"|"<< expr::format_date_time(expr::attr< boost::posix_time::ptime >("TimeStamp"), "%Y-%m-%d, %H:%M:%S.%f") << "|"<< boost::phoenix::bind(&get_native_process_id, process_id.or_none()) << ":"<< boost::phoenix::bind(&get_native_thread_id, thread_id.or_none()) << "|"/// @question 以下2行代码输出的内容怎么是空的?
//         << logging::expressions::attr<logging::attributes::current_thread_id::value_type>("ThreadID") << ":"
//      << logging::expressions::attr<logging::attributes::current_process_id::value_type>("ProcessID") <<  "|"<< "[" << expr::attr< severity_level, severity_tag >("Severity")<< "] " << expr::smessage));
}    

5.7add_global_attribute

    boost::shared_ptr< logging::core > core = logging::core::get();core->add_global_attribute("LineID", attrs::counter< unsigned int >(1));core->add_global_attribute("TimeStamp", attrs::local_clock());

5.8set_filter

方法1:

  logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::info);

方法2:对于自定义severity级别

  logging::core::get()->set_filter([](const logging::attribute_value_set& attr_set) {return attr_set["Severity"].extract<severity_level>() >= SL_WARNING;})  

5.9logging::init_from_settings

以下代码未验证

void init_logging() {logging::settings setts;setts["Core"]["Filter"] = "%Severity% >= warning";setts["Core"]["DisableLogging"] = false;// Subsections can be referred to with a single pathsetts["Sinks.Console"]["Destination"] = "Console";setts["Sinks.Console"]["Filter"] = "%Severity% >= fatal";setts["Sinks.Console"]["AutoFlush"] = true;// ...as well as the individual parameterssetts["Sinks.File.Destination"] = "TextFile";setts["Sinks.File.FileName"] = "MyApp_%3N.log";setts["Sinks.File.AutoFlush"] = true;setts["Sinks.File.RotationSize"] = 10 * 1024 * 1024; // 10 MiBlogging::init_from_settings(setts);
}

boost log使用相关推荐

  1. boost::log模块测试样板,用于检查每个公共标头是否都是独立的并且没有任何缺失的 #includes

    boost::log模块测试样板,用于检查每个公共标头是否都是独立的并且没有任何缺失的 #includes 实现功能 C++实现代码 实现功能 boost::log模块测试样板,用于检查每个公共标头是 ...

  2. boost::log模块测试get_attributes()这个const方法可以获取线程模型内部的互斥锁

    boost::log模块测试get_attributes这个const方法可以获取线程模型内部的互斥锁 实现功能 C++实现代码 实现功能 boost::log模块测试get_attributes() ...

  3. boost::log模块测量转储二进制数据的性能

    boost::log模块测量转储二进制数据的性能 实现功能 C++实现代码 实现功能 boost::log模块测量转储二进制数据的性能 C++实现代码 #include <cstdlib> ...

  4. boost::log模块测量日志记录发射的性能

    boost::log模块测量日志记录发射的性能 实现功能 C++实现代码 实现功能 boost::log模块测量日志记录发射的性能 C++实现代码 #define BOOST_NO_DYN_LINK ...

  5. boost::log模块测试检查插入不会使容器中的现有元素无效

    boost::log模块测试检查插入不会使容器中的现有元素无效 实现功能 C++实现代码 实现功能 boost::log模块测试检查插入不会使容器中的现有元素无效 C++实现代码 #define BO ...

  6. boost::log::attributes::make_function用法的测试程序

    boost::log::attributes::make_function用法的测试程序 实现功能 C++实现代码 实现功能 boost::log::attributes::make_function ...

  7. boost::log::attribute_value_set用法的测试程序

    boost::log::attribute_value_set用法的测试程序 实现功能 C++实现代码 实现功能 boost::log::attribute_value_set用法的测试程序 C++实 ...

  8. boost::log::parse_formatter用法的测试程序

    boost::log::parse_formatter用法的测试程序 实现功能 C++实现代码 实现功能 boost::log::parse_formatter用法的测试程序 C++实现代码 #def ...

  9. boost::log::string_literal用法的测试程序

    boost::log::string_literal用法的测试程序 实现功能 实现功能 boost::log::string_literal用法的测试程序# C++实现代码 #define BOOST ...

  10. boost::log::attribute_value用法的测试程序

    boost::log::用法的测试程序 实现功能 C++实现代码 实现功能 boost::log::用法的测试程序 C++实现代码 #include <cstddef> #include ...

最新文章

  1. 绝不能错过的10款最新OpenStack网络运维 监控工具
  2. PAT甲级1078 Hashing:[C++题解]哈希表、哈希表开放寻址法、二次探测法
  3. counter()函数和most_common()函数
  4. eclipse ldt update resource
  5. 牛客-Forsaken喜欢独一无二的树【并查集,最小生成树】
  6. Android应用程序消息处理机制(Looper、Handler)分析
  7. 3 运行时间太长_10大污水处理预处理系统动态图及运行管理、故障处理
  8. android exittext记事本,GUI练习——记事本
  9. windows中squid更改默认安装路径配置说明
  10. python中测试字符串类型的函数_Python新手学习基础之数据类型——字符串类型
  11. catia怎么将特征参数化_catia 怎么做参数化设计
  12. 密码安全攻防技术精讲
  13. 风铃魔兽世界同步器(5开10开N开)V3.1免费共享版
  14. Windows 域的简单说明
  15. gitbub图片 头像 图标不显示
  16. Unity3d常用快捷键
  17. 单兵渗透工具-Yakit-Windows安装使用
  18. 本次给大家来个简单的一元二次方程求解的编程
  19. 锁定计算机 背景图片,win7系统电脑更换锁屏壁纸的方法
  20. 正则校验必须由数字 字母 和 特殊符号组成的正则

热门文章

  1. js骚操作骂人不带脏
  2. HTML页面嵌入视频无法播放的常见原因
  3. 深入理解GAN对抗生成网络
  4. 17AHU排位赛3 C题 (LCS)
  5. 从囚徒困境到世风日下
  6. Mybatis多表新增
  7. h5+hbuilder 制作手机app
  8. 回顾一年的工作历程_但回首这一年来的工作经历
  9. 如何破解红蜘蛛(控屏软件)
  10. matlab中字体修改,matlab——修改图中字体