在 C++ 中提升日志记录和 'Object-like' 日志记录行为
Boost Logging and 'Object-like' Logging Behaviour in C++
几天来我一直在寻找 C++ 中的日志记录库,但不知何故我对 boost logging or Pantheios 等现有解决方案不太满意。我最初是一名 Java 开发人员。我想要一个带有记录器的日志记录库,它的行为更像一个对象。我想做以下事情:
- 创建日志记录对象的实例
Logger(filepath, filename)
- 并使用
log(serverity, message)
方法在文本文件中记录不同的消息
此功能的突出问题是我事先不知道将存在多少这些日志记录对象,或者这些文件是否具有相同的文件路径。也许我可以用 boost 来处理这个问题,但我没有在文档的 "Text multi-file backend" 部分得到 example 。特别是示例中的这段代码片段将做什么:
片段 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 个问题(或问题):
- 这是否意味着我只需要设置属性 RequestID,然后记录器将决定将消息放入哪个文件?我该怎么做?
- 是否可以使用 boost 将日志文件放在不同的路径中?
- 不同线程访问同一个文件会怎样?
- init_logging() 中的这段代码会影响 boost 日志库的应用程序范围的行为吗?这是通过某种...全局变量完成的吗?
可能是我的想法太天真了。有没有办法得到我在 post 开头提到的东西?
我认为您需要 log4cxx 日志库。当你将它写入日志文件时,它决定了日志级别。
这是您入门的参考。
http://www.yolinux.com/TUTORIALS/Log4cxx.html
如果您是 Boost.Log 的新手,您应该阅读有关库的信息 design first, it is quite different from Java. Despite the difference, it is possible to configure the library in a similar way to log4j, and 答案将帮助您入门。
现在,回答您的问题:
- Does that mean that I just have to set the attribute RequestID and than the logger will decide in which file to put the message? How would I do that?
在text_multifile_backend
the sink will decide to what file every log record will be written. The set_file_name_composer
call sets a function object that composes the log file name, and as you can see, it involves the RequestID attribute. Naturally, you can use whatever attribute(s) you like, including channels. You should also know that text_multifile_backend
is not the only way (and probably not the most efficient way) to achieve what you want. If the number of different log files is limited, it is typically better to add several text file sinks的特殊情况下,每个文件一个,并设置过滤,以便每个接收器接收自己的日志记录。我在上面链接的答案中描述了这种方法。
关于添加属性,根据用例和要添加到的属性集,有不同的方法。在通道的情况下,此属性由记录器自动提供,您只需使用通道名称创建记录器,您通过该记录器创建的每条日志记录都会将其作为属性附加。您指向的示例中的 RequestID 属性可以以任何可能的方式添加。下面是几个常见的例子:
- 它可以添加到记录器中 manually。这是典型的,如果您创建一个记录器来处理请求(在广义上 - 无论 'request' 在您的应用程序中意味着什么),并通过该记录器写入与请求处理相关的所有日志消息。
- 它可以作为 scoped attribute 添加到记录器中。如果您没有针对每个请求的专用记录器,但在某处有一个用于写入与请求处理相关的日志的公共记录器,这将很有用。
- 它可以作为范围属性添加到 thread-specific attributes。如果请求处理涉及程序不同部分的多个记录器,但在给定时间点只有一个线程(当前线程)正在处理特定请求,这将有所帮助。其他线程可能正在处理其他请求并设置它们自己的线程特定属性 - 它们不会干扰。
- Is it even possible with boost to have logging files in different paths?
当然可以。正如我所说,这可以通过向核心添加多个文件接收器来完成。就其本质而言,text_multifile_backend
已经可以写入多个文件。
- What will happen if different threads access the same file?
Boost.Log 支持多线程。在接收器级别,sink frontends implement thread synchronization. For instance, the synchronous_sink
前端将阻止竞争线程并发写入单个文件。日志记录可以同时写入不同 个接收器。
Loggers也有单线程和多线程的版本,后者做了额外的锁来保护其内部结构不被并发访问。但是,这种保护不会扩展到接收器(即,即使您使用 _mt
记录器,接收器前端仍然必须同步线程)。
- Will this code in init_logging() effect the application-wide behaviour of the boost logging library? Is this done by some kind of ... global variables?
Boost.Log中有多个单例,是的。最值得注意的是 logging core,您可以在其中注册所有接收器以及全局和特定于线程的属性。添加一个新的接收器将对整个应用程序产生影响,因为来自所有记录器的记录将开始进入该接收器(这就是为什么您通常应该在将接收器添加到核心之前配置接收器)。记录器本身与接收器无关,日志记录最终位于哪个接收器仅由过滤器定义。但正如我提到的,可以借助属性和过滤器将记录器和接收器关联起来,并以相关方式管理它们。您将必须编写一个包装器 class 来提供您描述的接口,并与 Boost.Log 记录器一起创建和配置相应的接收器。
几天来我一直在寻找 C++ 中的日志记录库,但不知何故我对 boost logging or Pantheios 等现有解决方案不太满意。我最初是一名 Java 开发人员。我想要一个带有记录器的日志记录库,它的行为更像一个对象。我想做以下事情:
- 创建日志记录对象的实例
Logger(filepath, filename)
- 并使用
log(serverity, message)
方法在文本文件中记录不同的消息
此功能的突出问题是我事先不知道将存在多少这些日志记录对象,或者这些文件是否具有相同的文件路径。也许我可以用 boost 来处理这个问题,但我没有在文档的 "Text multi-file backend" 部分得到 example 。特别是示例中的这段代码片段将做什么:
片段 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 个问题(或问题):
- 这是否意味着我只需要设置属性 RequestID,然后记录器将决定将消息放入哪个文件?我该怎么做?
- 是否可以使用 boost 将日志文件放在不同的路径中?
- 不同线程访问同一个文件会怎样?
- init_logging() 中的这段代码会影响 boost 日志库的应用程序范围的行为吗?这是通过某种...全局变量完成的吗?
可能是我的想法太天真了。有没有办法得到我在 post 开头提到的东西?
我认为您需要 log4cxx 日志库。当你将它写入日志文件时,它决定了日志级别。
这是您入门的参考。
http://www.yolinux.com/TUTORIALS/Log4cxx.html
如果您是 Boost.Log 的新手,您应该阅读有关库的信息 design first, it is quite different from Java. Despite the difference, it is possible to configure the library in a similar way to log4j, and
现在,回答您的问题:
- Does that mean that I just have to set the attribute RequestID and than the logger will decide in which file to put the message? How would I do that?
在text_multifile_backend
the sink will decide to what file every log record will be written. The set_file_name_composer
call sets a function object that composes the log file name, and as you can see, it involves the RequestID attribute. Naturally, you can use whatever attribute(s) you like, including channels. You should also know that text_multifile_backend
is not the only way (and probably not the most efficient way) to achieve what you want. If the number of different log files is limited, it is typically better to add several text file sinks的特殊情况下,每个文件一个,并设置过滤,以便每个接收器接收自己的日志记录。我在上面链接的答案中描述了这种方法。
关于添加属性,根据用例和要添加到的属性集,有不同的方法。在通道的情况下,此属性由记录器自动提供,您只需使用通道名称创建记录器,您通过该记录器创建的每条日志记录都会将其作为属性附加。您指向的示例中的 RequestID 属性可以以任何可能的方式添加。下面是几个常见的例子:
- 它可以添加到记录器中 manually。这是典型的,如果您创建一个记录器来处理请求(在广义上 - 无论 'request' 在您的应用程序中意味着什么),并通过该记录器写入与请求处理相关的所有日志消息。
- 它可以作为 scoped attribute 添加到记录器中。如果您没有针对每个请求的专用记录器,但在某处有一个用于写入与请求处理相关的日志的公共记录器,这将很有用。
- 它可以作为范围属性添加到 thread-specific attributes。如果请求处理涉及程序不同部分的多个记录器,但在给定时间点只有一个线程(当前线程)正在处理特定请求,这将有所帮助。其他线程可能正在处理其他请求并设置它们自己的线程特定属性 - 它们不会干扰。
- Is it even possible with boost to have logging files in different paths?
当然可以。正如我所说,这可以通过向核心添加多个文件接收器来完成。就其本质而言,text_multifile_backend
已经可以写入多个文件。
- What will happen if different threads access the same file?
Boost.Log 支持多线程。在接收器级别,sink frontends implement thread synchronization. For instance, the synchronous_sink
前端将阻止竞争线程并发写入单个文件。日志记录可以同时写入不同 个接收器。
Loggers也有单线程和多线程的版本,后者做了额外的锁来保护其内部结构不被并发访问。但是,这种保护不会扩展到接收器(即,即使您使用 _mt
记录器,接收器前端仍然必须同步线程)。
- Will this code in init_logging() effect the application-wide behaviour of the boost logging library? Is this done by some kind of ... global variables?
Boost.Log中有多个单例,是的。最值得注意的是 logging core,您可以在其中注册所有接收器以及全局和特定于线程的属性。添加一个新的接收器将对整个应用程序产生影响,因为来自所有记录器的记录将开始进入该接收器(这就是为什么您通常应该在将接收器添加到核心之前配置接收器)。记录器本身与接收器无关,日志记录最终位于哪个接收器仅由过滤器定义。但正如我提到的,可以借助属性和过滤器将记录器和接收器关联起来,并以相关方式管理它们。您将必须编写一个包装器 class 来提供您描述的接口,并与 Boost.Log 记录器一起创建和配置相应的接收器。