Я играю с Boost.Log в boost 1.54.0, чтобы увидеть, является ли это приемлемым вариантом для моего приложения. В общем, у меня нет проблем с буферизацией, поэтому я не собираюсь включать auto_flush или что-то еще … но я заметил, что сообщения, которые регистрируются перед вызовом fork()
дублируются, и мне интересно, если это потому, что они буферизуются, буфер дублируется при копировании образа процесса, а затем оба процесса в конечном итоге записывают свои копии буфера в файл журнала …
Поэтому я хотел бы просто выполнить ручную очистку журнала, только один раз, непосредственно перед тем, как позвонить. fork()
чтобы быть уверенным, что в памяти не осталось сообщений. Другими словами, я ищу что-то похожее на fflush()
, .flush()
, << flush
и т. д., которые я могу использовать в журнале наддува.
Я пытался использовать << flush
с журналом, но я все еще получаю дублированные сообщения, так что я не на 100% уверен, что он сбрасывается, и дубликаты вызваны какой-то другой проблемой, или он каким-то образом молча игнорирует << flush
…
Редактировать:
Я осмотрелся и обнаружил, что лог буста не безопасен для форка. Поэтому я должен добавить, что я не пытаясь использовать один и тот же журнал в родительском и дочернем процессах. У меня есть два сценария разветвления — в одном родительский объект немедленно завершает работу и дочерний контур (так что это должно быть безопасно), а в другом дочерний должен открыть свой отдельный файл журнала, так что это тоже должно быть безопасно … но я нужно выяснить, как близко приемник файла журнала, а затем открыть новый (в другом файле). Я полагаю, закрытие раковины также может быть способом заставить флеш …?
Ладно … Мне пришлось немного покопаться в буст-коде (но не слишком), и я обнаружил, что это работает:
Когда вы звоните 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) дочерний процесс немедленно закрывает приемник файлов и открывает новый приемник для журнала, который указывает на другой файл (из того, который использует родительский процесс) — I считать этот третий случай должен быть безопасным.
Еще более простой код (с тривиальной регистрацией):
#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;
}
Согласно моим тестам, флеш является методом блокировки. Я использую его только во время инициализации, поэтому, если там что-то не так, я знаю, где было выполнение.