boost log简介

文章目录

  • 前言
    • 编译过程
  • 一步步介绍boost-log
    • boost-log的hello world
    • boost-log的结构
    • boost-log的简单使用
  • 按需定制日志库 - 略

前言

boost日志库的使用,稍微有点难度。写个文档记录下。

参考资料:

  1. Boost.Log官方文档 – 还行,但读起来不是很顺 | 文档对应的中文翻译 – 翻译的很烂

  2. 《The Boost C++ Libraries》Chapter 62. Boost.Log – 还行,使用示例方式介绍,没有step by step。

  3. Boost日志库快速入门 - 网易云课堂视频|文档 – 是按照官方文档的思路来讲解的,很一般。好的讲解可以是这样的思路:是什么。为什么是这样。如果不这样,会踩哪些坑。有什么好的应用等。

编译过程

如果使用g++的命令行编译下一节的demo,有可能会碰到这个报错:Boost logger linking issue

可以将编译和连接过程分开:

g++ -DBOOST_LOG_DYN_LINK -c  hello_world.cpp
g++ hello_world.o -lboost_log -lpthread -o hello_world

还是用cmake吧。敲命令比较麻烦。可以参考我之前的博客:cmake下切换使用不同版本的boost-未解决

cmake_minimum_required(VERSION 3.11)

project(boost_test)

find_package(
    Boost REQUIRED
    COMPONENTS log)

include_directories(${Boost_INCLUDE_DIRS})

add_executable(${PROJECT_NAME} hello_world.cpp)

target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES})

一步步介绍boost-log


boost-log的hello world

BOOST_LOG_TRIVIAL宏用于启动日志记录。宏的参数指定以下严重级别之一:trace, debug, info, warning, error or fatal(请参阅 severity_level 枚举)。在宏之后,可能有一个组成记录消息字符串的流式表达式。例如:

#include 

int main(int argc, char* argv[])
{
    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;
}

日志消息将打印在控制台上。

[2022-06-02 17:43:03.268628] [0x00007f5c0ec83540] [trace]   A trace severity message
[2022-06-02 17:43:03.268657] [0x00007f5c0ec83540] [debug]   A debug severity message
[2022-06-02 17:43:03.268660] [0x00007f5c0ec83540] [info]    An informational severity message
[2022-06-02 17:43:03.268662] [0x00007f5c0ec83540] [warning] A warning severity message
[2022-06-02 17:43:03.268664] [0x00007f5c0ec83540] [error]   An error severity message
[2022-06-02 17:43:03.268666] [0x00007f5c0ec83540] [fatal]   A fatal severity message

该宏有以下特点 :除了记录消息,输出中的每条日志记录都包含时间戳、当前线程标识和严重性级别;从不同线程并发写入日志是安全的,日志消息不会被破坏。


boost-log的结构

我看了好几遍boost-log的Design overview。我大体知道是咋回事,但不是很清楚,所以没法详细说明。这里,我们简单介绍下。毕竟,了解结构,对于使用和理解API是非常有好处的。

boost-log库由三层组成:the layer of log data collection(收集日志层), the layer of processing the collected data(处理收集到的日志数据),连接这两层的中间层。(只有一个logging core。如何实现将不同的日志,写入两个不同日志文件呢?出现这个问题应该是logging sources没有和sink建立联系。)(可以参考:Boost.log: How to prevent the output will be duplicated to all added streams when it uses the add_file_log() function?)

boost log简介_第1张图片

箭头显示日志信息流的方向 - 从左侧的应用程序部分到右侧的最终存储(如果有)。

Logging sources:最左侧那列。Embedded logger应该是可以定义在局部范围的logger,比如定义在类内部。Global loggers是全局的logger,大家都可以调用。custom log sources不知道,看起来像是可以自定义log的来源。

Attributes and attribute values:上一节示例的log输出包含时间戳。获取时间戳的函数可以认为是一个属性,而具体的时间戳则是属性值。属性值有三种:global、thread-specific、source-specific。

Logging core and filtering:core是单例。在这里设置过滤,是一个全局过滤。还有些介绍,没看懂。

Sinks and formatting:正如您在上图中可能已经注意到的那样,接收器由两部分组成:前端和后端。进行这种划分是为了将接收器的通用功能(例如过滤、格式化和线程同步)提取到单独的实体(前端)中。接收器前端由库提供,用户很可能不必重新实现它们。另一方面,后端是最有可能扩展库的地方之一。实际处理日志记录的是接收器后端。可以有一个将日志记录存储到文件中的接收器;可以有一个接收器通过网络将日志记录发送到远程日志处理节点;可以有前面提到的接收器将记录消息放入工具提示通知中 - 你可以命名它。


boost-log的简单使用

我希望日志有以下功能/特性:

  • 日志可以限定级别。例如,只有info及以上级别的日志会记录。
  • 日志写入文件,而非标准输出。
  • 日志不能总写在一个文件里面。可以按照时间或者日志大小的变化,写入新的文件。
  • 可以自定义日志的输出格式(属性:时间戳等)。
  • 线程安全。

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

// 为了是代码简介,我们给命名空间取个别名
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;
namespace trivial = boost::log::trivial;

void init()
{   
#ifdef Debug
    logging::core::get()->set_filter(
        trivial::severity >= trivial::debug
    );
#else
    logging::core::get()->set_filter(
        trivial::severity >= trivial::info
    );
#endif

    logging::add_file_log(
        keywords::file_name ="sample_%N.log", // 日志名为sample_0.log,sample_1.log
        keywords::open_mode = std::ios_base::app, // 日志使用追加方式
        keywords::rotation_size = 1 * 1024 * 1024, // 当日志大小到1M的时候,使用新的日志文件存储
        keywords::format = "[%TimeStamp%]: <%Severity%> %Message%"); // 每条日志的输出格式:时间,日志等级,日志信息

    logging::add_common_attributes();    
}

int main(int argc, char* argv[])
{
    src::severity_logger_mt lg;

    init();

    BOOST_LOG_SEV(lg, trivial::info) << "Simple use of Boost log";
}

在编写这个demo的时候,我遇到过这两个问题:error: ‘severity’ is not a member of ‘boost::log::v2s_mt_posix::trivial’、formatter_parser.hpp: undefined reference to `boost::log::v2_mt_posix::basic_formatter boost::log::v2_mt_posix::parse_formatter

其中的第二个问题,使用介绍的方法解决。暂时没有究竟为什么会解决。

而,第一个问题是由于缺少头文件引起的。我应该在第一时间想到,命名空间中的内容,被分开定义在不同的头文件中。

可以看到demo的代码不长,但是引用了一堆头文件。为此,我特意到/usr/include/boost/log中看来boost-log的头文件分布。。

按照上一节的结构图,我们来看下上面这段代码。

logger source

这玩意定义在boost::log::sources的命名空间中。关于日志源的文档,可参考Logging sources。我只看了Loggers with severity level support

我们使用src::severity_logger_mt lg;创建了一个局部的logger源。severity_logger_mt是一个线程安全的looger,它将日志级别的属性添加到每个日志条目。我们可以使用宏BOOST_LOG_SEV来设置日志级别。

Attributes and attribute values

logging::add_common_attributes()给我们添加了四个常见属性:LineID、TimeStamp、ProcessID、ThreadID。severity_logger_mt给我们添加了Severity。如果没有添加属性,当在format中指定的时候,对应的内容将会为空,比如why my format doesn’t work in boost log、boost log severity empty in the log message、Boost Log 2.0 : empty Severity level in logs

core

维护全局和线程特定的属性集。我们根据#ifdef Debug,在core设置过滤器。可以参考core-Detailed features description

Sinks and formatting

sink front end用于过滤、格式化和线程同步。sink back end用于将日志输出。上面示例,我们使用add_file_log将日志写入文件。(如果想要日志分流,则需要定制前后sink)


按需定制日志库 - 略

你可能感兴趣的:(#,环境编程,boost,log)