【问题标题】:Boost Logging and 'Object-like' Logging Behaviour in C++在 C++ 中提升日志记录和“类似对象”的日志记录行为
【发布时间】:2025-12-28 09:10:12
【问题描述】:

我已经用 C++ 搜索了几天的日志库,但不知何故,我对现有的解决方案(如 boost loggingPantheios)不太满意。最初我是一名 Java 开发人员。我想要一个日志库,它的行为更像一个对象。我想做以下事情:

  1. 创建日志对象的实例Logger(filepath, filename)
  2. 并使用log(serverity, message) 方法在文本文件中记录不同的消息

此功能的突出问题是我事先不知道这些日志记录对象将存在多少,或者这些文件是否具有相同的文件路径。也许我可以用 boost 来处理这个问题,但我没有在文档的“文本多文件后端”部分得到 example。特别是示例中的这段代码 sn-ps 将做什么:

片段 1.

 // 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")
    );

片段 2。

 // Set the formatter
    sink->set_formatter
    (
        expr::stream
            << "[RequestID: " << expr::attr< std::string >("RequestID")
            << "] " << expr::smessage
    );

这段代码在我脑海中提出了 4 个问题(或多个问题):

  1. 这是否意味着我只需要设置属性 RequestID 并且记录器将决定将消息放入哪个文件?我该怎么做?
  2. 甚至可以通过 boost 将日志文件放在不同的路径中吗?
  3. 如果不同的线程访问同一个文件会发生什么?
  4. init_logging() 中的这段代码会影响boost 日志库的应用程序范围的行为吗?这是由某种......全局变量完成的吗?

也许我的想法太天真了。有没有办法得到我在帖子开头提到的东西?

【问题讨论】:

    标签: c++ logging boost boost-log


    【解决方案1】:

    如果您是 Boost.Log 的新手,您应该首先阅读库 design,它与 Java 完全不同。尽管存在差异,但可以以与 log4j 类似的方式配置库,this 答案将帮助您入门。

    现在,回答您的问题:

    1. 这是否意味着我只需要设置属性 RequestID 并且记录器将决定将消息放入哪个文件?我该怎么做?

    text_multifile_backend 的特殊情况下,接收器将决定将每个日志记录写入哪个文件。 set_file_name_composer 调用设置了一个构成日志文件名的函数对象,如您所见,它涉及到 RequestID 属性。当然,您可以使用任何您喜欢的属性,包括channels。您还应该知道text_multifile_backend 不是实现您想要的唯一方法(也可能不是最有效的方法)。如果不同日志文件的数量有限,通常最好添加几个text file sinks,每个文件一个,并设置过滤,以便每个接收器接收自己的日志记录。我在上面链接的答案中描述了这种方法。

    关于添加属性,有不同的方法,具体取决于用例和要添加到的属性集。对于通道,此属性由记录器自动提供,您只需使用通道名称创建记录器,您通过该记录器创建的每条日志记录都会将其作为属性附加。您指向的示例中的 RequestID 属性可以以任何可能的方式添加。以下是一些常见的例子:

    • 它可以添加到记录器manually。这是典型的情况,如果您创建一个用于处理请求的记录器(广义上 - 应用程序中的任何“请求”含义),并通过该记录器写入与请求处理相关的所有日志消息。
    • 它可以作为scoped attribute 添加到记录器中。如果您没有针对每个请求的专用记录器,但在某处有一个通用记录器用于写入与请求处理相关的日志,这将非常有用。
    • 它可以作为范围属性添加到thread-specific attributes。如果请求处理涉及程序不同部分的多个记录器,这将有所帮助,但在给定的时间点,只有一个线程(当前线程)正在处理特定的请求。其他线程可能正在处理其他请求并设置自己的线程特定属性 - 它们不会干扰。
    1. 甚至可以通过 boost 将日志文件放在不同的路径中吗?

    当然。正如我所说,这可以通过向核心添加多个文件接收器来完成。就其本质而言,text_multifile_backend 已经能够写入多个文件。

    1. 如果不同的线程访问同一个文件会发生什么?

    Boost.Log 支持多线程。在 sink 层面,sink frontends 实现线程同步。例如,synchronous_sink 前端将阻止竞争线程同时写入单个文件。不过,日志记录可以同时写入不同的个接收器。

    Loggers 也有单线程和多线程版本,后者做了额外的锁定以保护其内部结构不被并发访问。但是,这种保护不会扩展到接收器(即,即使您使用 _mt 记录器,接收器前端仍然必须同步线程)。

    1. init_logging() 中的这段代码会影响boost 日志库的应用程序范围的行为吗?这是由某种...全局变量完成的吗?

    Boost.Log 中有许多单例,是的。最值得注意的是logging core,您可以在其中注册所有接收器以及全局和线程特定的属性。添加一个新的接收器将对整个应用程序产生影响,因为来自所有记录器的记录将开始进入该接收器(这就是为什么通常应该在将接收器添加到核心之前配置接收器的原因)。记录器本身与接收器无关,并且日志记录最终在哪个接收器中仅由过滤器定义。但正如我所提到的,可以在属性和过滤器的帮助下关联记录器和接收器,并以相关的方式管理它们。您必须编写一个包装类来提供您描述的接口,并与 Boost.Log 记录器一起创建和配置相应的接收器。

    【讨论】:

    • 非常感谢您的回答。我已经弄清楚了你自己提到的一些事情(例如核心、汇和源之间的关系)。在接下来的几天里,我将更深入地研究其他内容。 This post 对我的特定问题也很有用。我想我可以按照我需要的方式使用 boost。它非常广泛,但在第一次运行时很难把所有东西都做好。
    【解决方案2】:

    我认为您需要 log4cxx 日志库。它在您将其写入日志文件时确定日志级别。
    这是您入门的参考。 http://www.yolinux.com/TUTORIALS/Log4cxx.html

    【讨论】:

    • 我会试试 Log4cxx。但是..只是因为我很好奇。也许有人回答了我的其他问题 (1-4)?
    • log4cxx 是否仍由 Apache 维护? Because some say it is dead.
    • 不确定,因为我们在早期的项目中使用过它。该项目肯定仍然运行良好,我认为无论如何你都需要支持它。据我记得它整洁的库和使用它编写的代码可以很好地维护。希望这会有所帮助。