Как я могу вручную очистить журнал повышения?

Я играю с Boost.Log в boost 1.54.0, чтобы посмотреть, подходит ли это для моего приложения. В общем, у меня нет проблем с буферизацией, поэтому я не собираюсь включать auto_flush или что-то еще... но я заметил, что сообщения, которые регистрируются до того, как я вызову fork(), дублируются, и мне интересно, если это потому, что они буферизованы, буфер дублируется при копировании образа процесса, а затем оба процесса в конечном итоге записывают свои буферные копии в файл журнала...

Итак, в основном, я хотел бы просто выполнить ручную очистку журнала, только один раз, непосредственно перед тем, как я вызову fork(), чтобы убедиться, что в памяти все еще нет сообщений. Другими словами, я ищу что-то вроде fflush(), .flush(), << flush и т. д., что я могу использовать в журнале повышения.

Я пытался использовать << flush с журналом, но я все еще получаю дублированные сообщения, поэтому я не уверен на 100%, вызваны ли они очисткой и дубликатами какой-то другой проблемой, или он каким-то образом молча игнорирует << flush...

Изменить:

Я осмотрелся и обнаружил, что журнал повышения не является безопасным для форка. Поэтому я должен добавить, что я не пытаюсь использовать один и тот же журнал в родительском и дочернем процессах. У меня есть два сценария разветвления: в одном родительский процесс завершается немедленно, а дочерний непрерывен (так что это должно быть безопасно), а в другом дочерний элемент должен открывать свой собственный отдельный файл журнала, так что это также должно быть безопасным ... но я нужно выяснить, как закрыть приемник файла журнала, а затем открыть новый (в другом файле). Я полагаю, что закрытие раковины также может быть способом вызвать смыв...?


person Dave Lillethun    schedule 26.07.2013    source источник
comment
Возможно, вы можете добавить канал журнала, который вы слушаете, а затем записываете одно сообщение. Как только вы получили это сообщение на своем канале, вы можете удалить канал, и вы готовы к форку.   -  person StackedCrooked    schedule 26.07.2013


Ответы (2)


Хорошо... Мне пришлось немного покопаться в коде повышения (но не слишком много), и я нашел это, которое, похоже, работает:

Когда вы вызываете 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) дочерний процесс немедленно закрывает приемник файлов и открывает новый приемник для журнала, который указывает на другой файл (из того, который использует родительский процесс) - я думаю, что этот третий случай должен быть безопасным.

person Dave Lillethun    schedule 26.07.2013

Еще более простой код (с тривиальным логированием):

#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;
}

Согласно моим тестам, флеш — это метод блокировки. Я использую его только во время инициализации, поэтому, если что-то не так, я знаю, где было выполнение.

person Paweł Szczur    schedule 31.12.2013