如何手动冲洗升压日志?

时间:2013-07-26 18:32:40

标签: c++ boost flush boost-log boost-logging

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

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

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

修改

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

2 个答案:

答案 0 :(得分:5)

好的......我不得不深入研究一下增强代码(但不是太多),我找到了这个,这似乎有用:

当您致电add_file_log(strLogFilename)时,它会返回shared_ptr<sink>,其中sink是您的接收器类型(例如shared_ptr< synchronous_sink< text_file_backend > >)。如果你改为创建你的接收器&#34;手动&#34;当然你也有一个指向它的指针......似乎接收器和后端都有一个.flush()方法。我不确定如何直接获得后端的副本来调用它的刷新,但是接收器上的刷新似乎只是在其后端调用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

在我的例子中,它的安全性只是因为父进程在分叉后立即退出而根本没有触及日志(在fork之后)。因此,对日志没有任何争用。

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

答案 1 :(得分:5)

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

#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是一种阻止方法。我只在初始化期间使用它,所以如果发生错误,我知道执行的位置。