log

简易demo

  • -lboost_log -lboost_system -lboost_thread -lboost_filesystem
  • -DBOOST_LOG_DYN_LINK
  • 输出所有信息到控制台
#include <iostream>
#include <boost/log/trivial.hpp>
 
using namespace std;
namespace logging = boost::log;
namespace sinks = boost::log::sinks;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace attrs = boost::log::attributes;
namespace keywords = boost::log::keywords;

static void simple_example()
{
  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";
}

设置filter

#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>


static void boost_log::set_filter_example()
{
    logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::info);
    simple_example();
    logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::warning);
    simple_example();
}

注意

  • 在我的TCP服务中,可以监听一个管理端口,专门用来接受用于改变过滤级别的特殊消息。

设置输出到文件

#include <boost/log/utility/setup/file.hpp>
static void write_to_file_example()
{
    logging::add_file_log("sample.log");
    set_filter_example();
}

设置回滚

#include <boost/log/trivial.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> 
static void boost_log::roll_back_file_example()
{
    boost::log::register_simple_formatter_factory<boost::log::trivial::severity_level, char>("Severity");
    logging::add_file_log(

            keywords::file_name = "./sign_%Y-%m-%d_%N.log",//"./sign_%Y-%m-%d_%H-%M-%S.%N.log",
            keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0),
            keywords::format = "[%TimeStamp%]  (%Severity%): %Message%",
            keywords::auto_flush = true,

            keywords::target = "./",
            keywords::max_files = 3,
            keywords::rotation_size = 1 * 1024 * 1024
    );
    logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::debug);
    logging::add_common_attributes();

}

注意

  • -lboost_log_setup

架构

Design

说明

左边是 log source, 负责从程序中收集日志信息,就像这样的语句:

BOOST_LOG_TRIVIAL(trace) << "A trace severity message";

右边是sink, 负责处理日志信息,决定日志输出到哪里,怎么使用。

中间的logging core将它们连接在一起。


获得core

#include <boost/log/core.hpp>
...
boost::shared_ptr<logging::core> core = logging::core::get();

如何安装Sink对象

一个core可以安装多个Sink,下面的代码假定已经有了两个Sink对象,将其安装到core中

  core->add_sink(sink1);
//...
  core->add_sink(sink2);

如何创建一个Sink对象

需要先创建一个backend对象,然后在创建sink对象的时候,将backend对象传递给它。

 typedef sinks::synchronous_sink<sinks::text_file_backend> TextSink;
  // init sink1
  boost::shared_ptr<sinks::text_file_backend> backend1 = 	      boost::make_shared<sinks::text_file_backend>(
		  keywords::file_name = "sign_%Y-%m-%d_%H-%M-%S.%N.log",
		  keywords::rotation_size = 10 * 1024 * 1024,
		  keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0),
		  keywords::min_free_space = 30 * 1024 * 1024);
  boost::shared_ptr<TextSink> sink1(new TextSink(backend1));

如何定义自己的severity level

  • 注释掉namespace logging::trivial

  • 定义自己的enum

    • enum sign_severity_level {
        trace,
        debug,
        info,
        warning,
        error,
        fatal,
        report
      };
      
  • 修改两个sink的日志格式:(注意expr::attr<sign_severity_level> 这行)

    sink1->set_formatter (
       expr::format("[%1%]<%2%>(%3%): %4%")
       % expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
       % expr::attr<sign_severity_level>("Severity")
       % expr::attr<attrs::current_thread_id::value_type >("ThreadID")
       % expr::smessage
       );
    
  • 用新的enum创建logger

  • 修改sink2的filter

例子


#include <fstream>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/thread/thread.hpp>
#include <boost/log/attributes/scoped_attribute.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;
//using namespace logging::trivial;
enum sign_severity_level {
  trace,
  debug,
  info,
  warning,
  error,
  fatal,
  report
};
void InitLog() {
  typedef sinks::synchronous_sink<sinks::text_ostream_backend> text_sink;
  boost::shared_ptr< text_sink > sink1 = boost::make_shared<text_sink>();
  sink1->locked_backend()->add_stream(
          boost::make_shared< std::ofstream >("sign.log"));
  sink1->set_formatter (
   expr::format("[%1%]<%2%>(%3%): %4%")
   % expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
   % expr::attr<sign_severity_level>("Severity")
   % expr::attr<attrs::current_thread_id::value_type >("ThreadID")
   % expr::smessage
   );
  logging::core::get()->add_sink(sink1);
  sink1->set_filter(expr::attr<sign_severity_level>("Severity") >= warning);
  boost::shared_ptr< text_sink > sink2 = boost::make_shared< text_sink >();
  sink2->locked_backend()->add_stream(
          boost::make_shared< std::ofstream >("sign.csv"));
  sink2->set_formatter (
   expr::format("%1%,%2%,%3%")
   % expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
   % expr::attr<sign_severity_level>("Severity")
   % expr::smessage
   );
  logging::core::get()->add_sink(sink2);
  sink2->set_filter(expr::attr<sign_severity_level>("Severity") == report);
  logging::add_common_attributes();
  //  BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id());
  logging::core::get()->add_global_attribute("ThreadID", attrs::current_thread_id());
}
int main(int, char*[]) {
  InitLog();
  src::severity_logger<sign_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";
  BOOST_LOG_SEV(lg, report) << "A report severity message";
  logging::core::get()->remove_all_sinks();
  return 0;
}

全局logger对象

  • 创建一个logger.h文件,只有一行:
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::severity_logger_mt<sign_severity_level>)
  • 在main.cc文件中,include必须的头文件,然后使用my_logger::get()方法获取logger对象的引用
#include <fstream>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread/thread.hpp>
 
#include <boost/log/core.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/common.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/sources/logger.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/formatter_parser.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/severity_feature.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;
enum sign_severity_level {
  trace,
  debug,
  info,
  warning,
  error,
  fatal,
  report
};
void InitLog() {
  typedef sinks::synchronous_sink<sinks::text_ostream_backend> text_sink;
  boost::shared_ptr< text_sink > sink1 = boost::make_shared<text_sink>();
  sink1->locked_backend()->add_stream(
          boost::make_shared<std::ofstream>("sign.log"));
  sink1->set_formatter (
   expr::format("[%1%]<%2%>(%3%): %4%")
   % expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
   % expr::attr<sign_severity_level>("Severity")
   % expr::attr<attrs::current_thread_id::value_type >("ThreadID")
   % expr::smessage
   );
  logging::core::get()->add_sink(sink1);
  sink1->set_filter(expr::attr<sign_severity_level>("Severity") >= warning);
  boost::shared_ptr< text_sink > sink2 = boost::make_shared< text_sink >();
  sink2->locked_backend()->add_stream(
          boost::make_shared< std::ofstream >("sign.csv"));
  sink2->set_formatter (
   expr::format("%1%,%2%,%3%")
   % expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
   % expr::attr<sign_severity_level>("Severity")
   % expr::smessage
   );
  logging::core::get()->add_sink(sink2);
  sink2->set_filter(expr::attr<sign_severity_level>("Severity") == report);
  logging::add_common_attributes();
  logging::core::get()->add_global_attribute("ThreadID", attrs::current_thread_id());
}
#include "logger.h"
int main(int, char*[]) {
  InitLog();
  src::severity_logger_mt<sign_severity_level>& lg = my_logger::get();
  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";
  BOOST_LOG_SEV(lg, report) << "A report severity message";
  return 0;
}

如何创建一个backend对象

指定frontend类型

  • 前面的代码中已经演示,注意backend的类型需要制定一个frontend类型作为其模板类。
  • 因此,当创建一个backend对象的时候,已经确定了frontend。
  • 这个frontend模板可以用synchronous_sink类,也可以用asynchronous_sink, 后者不会阻塞调用程序,会额外的创建线程去处理log,不过会慢点,内存消耗大点。一般都推荐先用后者。

例子1

  • 将直接使用sink,而不用add_file_log 函数的帮助。
  • 这个例子显示了如何格式化日志,将sink注册到core中,写日志到本地文件。完整的代码在下面。
#include <fstream>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/thread/thread.hpp>
#include <boost/log/attributes/scoped_attribute.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;
void InitLog() {
  typedef sinks::synchronous_sink< sinks::text_ostream_backend > text_sink;
  boost::shared_ptr< text_sink > sink = boost::make_shared< text_sink >();
  sink->locked_backend()->add_stream(
				     boost::make_shared< std::ofstream >("sign.log"));
  sink->set_formatter (
		       expr::format("[%1%]<%2%>(%3%): %4%")
		       % expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
		       % logging::trivial::severity
		       % expr::attr<boost::log::attributes::current_thread_id::value_type >("ThreadID")
		       % expr::smessage
		       );
  logging::core::get()->add_sink(sink);
  logging::add_common_attributes();
  BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id());
}
int main(int, char*[]) {
  InitLog();
  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;
}

例子2

  • 演示如何在一个程序中使用两个sink. 这两个sink有不同的filter,生成两个日志文件,采用不同的日志格式。
  • 创建了sink1 和 sink2对象。sink1输出sign.log文件,sink2输出sign.csv文件。
  • 所有严重级别大于等于warning的日志会出现在sign.log文件中,
  • 所有低于warning的日志会被记录在sign.csv文件中,并以csv格式保存。

#include <fstream>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/thread/thread.hpp>
#include <boost/log/attributes/scoped_attribute.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;
using namespace logging::trivial;
void InitLog() {
  typedef sinks::synchronous_sink< sinks::text_ostream_backend > text_sink;
  boost::shared_ptr< text_sink > sink1 = boost::make_shared< text_sink >();
  sink1->locked_backend()->add_stream(
         boost::make_shared< std::ofstream >("sign.log"));
  sink1->set_formatter (
         expr::format("[%1%]<%2%>(%3%): %4%")
         % expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
         % logging::trivial::severity
         % expr::attr<boost::log::attributes::current_thread_id::value_type >("ThreadID")
         % expr::smessage
         );
  logging::core::get()->add_sink(sink1);
  sink1->set_filter(expr::attr< severity_level >("Severity") >= warning);
    
  boost::shared_ptr< text_sink > sink2 = boost::make_shared< text_sink >();
  sink2->locked_backend()->add_stream(
         boost::make_shared< std::ofstream >("sign.csv"));
  sink2->set_formatter (
         expr::format("%1%,%2%,%3%")
         % expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S")
         % logging::trivial::severity
         % expr::smessage
         );
  logging::core::get()->add_sink(sink2);
  sink2->set_filter(expr::attr< severity_level >("Severity") < warning);
    
  logging::add_common_attributes();
  BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id());
}
int main(int, char*[]) {
  InitLog();
  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;
}