6

我在 boost 1.54.0 中使用 Boost.Log 来查看它是否对我的应用程序来说是一个可行的选择。一般来说,我的缓冲没有问题,所以我不想打开 auto_flush 或任何东西......但我注意到在我调用之前记录的消息fork()是重复的,我想知道它是否是因为它们是缓冲的,所以在复制进程映像时缓冲区会被复制,然后两个进程最终都会将它们的缓冲区副本写入日志文件......

所以基本上,我只想在我打电话之前对日志进行一次手动刷新,fork()以确保没有消息仍在内存中。换句话说,我正在寻找可以在提升日志上使用的类似于fflush().flush()、等的东西。<< flush

我确实尝试过使用<< flush日志,但我仍然收到重复的消息,所以我不能 100% 确定它是否正在刷新并且重复是由其他问题引起的,或者它是否以某种方式默默地忽略了<< flush...

编辑:

我环顾四周,发现 boost log 不是 fork-safe。所以我应该补充一点,我并没有尝试在父进程和子进程中使用相同的日志。我有两种分叉场景 - 一种是父母立即终止并且孩子继续(这样应该是安全的),另一种是孩子应该打开自己的单独日志文件,所以这也应该是安全的......但我需要弄清楚如何关闭日志文件接收器,然后打开一个新的接收器(在不同的文件上)。我想关闭水槽也可能是强制冲洗的一种方式......?

4

2 回答 2

7

更简单的代码(使用简单的日志记录):

#include <boost/filesystem.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/utility/setup/file.hpp>

namespace logging = boost::log;

void InitLogging() {
  boost::filesystem::path full_path(boost::filesystem::current_path());

  auto sink = logging::add_file_log("sample.log");
  BOOST_LOG_TRIVIAL(info) << "Log initialized.";
  BOOST_LOG_TRIVIAL(info) << "Working dir: " << full_path;
  sink->flush();
}

int main() {
  InitLogging();
  return 0;
}

根据我的测试,flush 是一种阻塞方法。我只在初始化期间使用它,所以如果那里发生错误,我知道执行在哪里。

于 2013-12-31T14:58:25.050 回答
7

Okies...我不得不稍微研究一下boost代码(但不要太多),我发现了这个,这似乎有效:

当您调用add_file_log(strLogFilename)它时,它会返回您的接收器类型shared_ptr<sink>在哪里sink(例如,shared_ptr< synchronous_sink< text_file_backend > >)。如果您改为“手动”创建接收器,那么您当然也有一个指向它的指针......看起来接收器和后端都有一个.flush()方法。我不确定你如何直接获取后端的副本来调用它的刷新,但是接收器上的刷新似乎只是在其后端调用刷新,所以这是有效的。这是我发现对我有用的一些示例代码:

shared_ptr< synchronous_sink< text_file_backend > > pLogSink = add_file_log(strLogFilaname);
BOOST_LOG_TRIVIAL(debug) << "Boost log!";

// other work goes here

BOOST_LOG_TRIVIAL(debug) << "About to fork...";
if (pLogSink)
  pLogSink->flush();
pid_t pid = fork();

if (pid < 0)
  // handle error
else if (pid > 0)
  exit(EXIT_SUCCESS); // parent terminates
assert(0 == pid); // child continues

BOOST_LOG_TRIVIAL(debug) << "Fork succeeded!";

使用这种方法,我现在只能看到每条日志消息一次。当然,请记住有关将 Boost.Log 与 fork() 混合的警告... http://boost-log.sourceforge.net/libs/log/doc/html/log/rationale/fork_support.html

在我的示例中,这只是因为父进程在分叉后立即退出而不接触日志(在分叉之后)是安全的。因此,日志没有任何争用。

尽管有这些限制,但我可以看到在以下几种情况下使用它:1)守护进程(实际上这是我在这里尝试做的),2)fork-exec 模式(与Boost.Log配合得很好,根据上面的 URL),或 3)子进程立即关闭文件接收器并为指向不同文件的日志打开一个新接收器(来自父进程正在使用的文件) - 我认为这第三种情况应该是安全的.

于 2013-07-26T20:57:11.817 回答