BOOST_LOG_TRIVIAL vs logrotate (открыть журнал)

У меня есть программа, которая работает в качестве службы в течение длительного времени. я использую BOOST_LOG_TRIVIAL(info) << "Message" для регистрации различных событий. Я хотел бы сотрудничать с logrotate и снова откройте мой лог-файл после поворота. Теоретически сценарий работает следующим образом:

  • Моя программа запускается, происходит некоторая регистрация
  • Лог переименован из something.log в something.log.1 другой программой, такой как logrotate или мной вручную.
  • Моя программа продолжает входить в something.log.1 файл.
  • Я посылаю SIGHUP (или что-то) в мою программу, чтобы я мог снова открыть файл журнала. Но я не знаю как.

Мой подготовленный пример до сих пор (может и не понадобиться):

#include <iostream>
#include <stdexcept>

#include <csignal>

#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/support/date_time.hpp>

inline
void setupLogging(std::string const &logFileName)
{
namespace logging = boost::log;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace keywords = boost::log::keywords;
logging::add_common_attributes();
auto format = expr::stream
<< expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S.%f")
<< " progname " << logging::trivial::severity
<< ": " << expr::smessage;
auto fileOutput = logging::add_file_log(
keywords::file_name = logFileName, keywords::format = format
, keywords::auto_flush = true, keywords::open_mode = std::ios::app
);
auto consoleOutput = logging::add_console_log(
std::cerr, keywords::format = format, keywords::auto_flush = true
);
BOOST_LOG_TRIVIAL(debug) << "CHECKPOINT @ setupLogging() after log initialization.";
}

void my_signal_handler(int signal)
{
BOOST_LOG_TRIVIAL(info) << "my_signal_handler BEGIN";
/* REOPEN LOG HERE */
BOOST_LOG_TRIVIAL(info) << "my_signal_handler END";
}

int main()
{
setupLogging("logrotate.test.log");
if(signal(SIGHUP, my_signal_handler) == SIG_ERR)
{
BOOST_LOG_TRIVIAL(error) << "Failed to register signal handler";
return 1;
} else
BOOST_LOG_TRIVIAL(info) << "Signal handler registered.";
BOOST_LOG_TRIVIAL(info) << "CHECKPOINT 0";
for(size_t i=1; i<100; ++i)
{
boost::this_thread::sleep_for( boost::chrono::seconds(1) );
BOOST_LOG_TRIVIAL(info) << "CHECKPOINT " << i;
}
return 0;
}

Компиляция:

LINK="-lboost_system -lboost_date_time -lboost_log -lboost_log_setup -lboost_thread -lboost_chrono -lpthread"g++ -std=c++11 -Wextra -DBOOST_LOG_DYN_LINK -pedantic -O3 logrotate_test.cpp -o logrotate_test $LINK

Исходный код представления ответа Адама

namespace detail666777888
{
using namespace boost;
using namespace boost::log;
typedef shared_ptr< sinks::synchronous_sink< sinks::text_file_backend > > T;
}
typedef detail666777888::T SPFileSink;
SPFileSink logFileSink;

void setupLogging(...){
... logFileSink = logging::add_file_log ...
}

void my_sighup_handler(int /*signal*/)
{
BOOST_LOG_TRIVIAL(info) << "my_sighup_handler START";
auto oldLFS = logFileSink;
setupLogging("logrotate.test.log");
boost::log::core::get()->remove_sink(oldLFS);
BOOST_LOG_TRIVIAL(info) << "my_sighup_handler FINISH";
}

2

Решение

Просто используйте copytruncate опция logrotate.

Из руководства:

Обрезать исходный файл журнала на месте после создания копии, вместо
переместить старый файл журнала и при необходимости создать новый. Оно может
использоваться, когда какая-либо программа не может закрыть свой лог-файл и, таким образом,
может продолжить запись (добавление) в предыдущий файл журнала навсегда.
Обратите внимание, что между копированием файла очень маленький промежуток времени
и обрезать его, так что некоторые данные журнала могут быть потеряны. Когда это
опция используется, опция создания не будет иметь никакого эффекта, так как старый журнал
файл остается на месте.

http://linux.die.net/man/8/logrotate

РЕДАКТИРОВАТЬ:

Попробуй это. Взгляни на add_file_log[1] Исходный код функции. Затем:

  1. запомните объект, который вы добавили с помощью add_file_log (он возвращает сток)
  2. когда вы получаете сигнал remove_sink[2] и добавьте новую раковину с add_file_log[1] — (записи в журналах могут просочиться, когда они генерируются другим потоком)
[1] http://www.boost.org/doc/libs/1_55_0/boost/log/utility/setup/file.hpp

[2] http://www.boost.org/doc/libs/1_55_0/boost/log/core/core.hpp

1

Другие решения

Я столкнулся с той же проблемой и нашел довольно простое решение: просто инициализировать text_file_backend с одним именем файла (без шаблона вообще) и вызов text_file_backend::rotate_file(), Это закроет текущий файл и откроет новый с тем же именем.

// create sink
auto backend = boost::make_shared< boost::log::sinks::text_file_backend >(
boost::log::keywords::file_name = "my.log",
boost::log::keywords::open_mode = std::ios_base::out | std::ios_base::app
);
auto sink = boost::make_shared<sinks::synchronous_sink<boost::log::sinks::text_file_backend>>(backend);
boost::log::core::get()->add_sink(sink);

// ... do some logging

// move log file and...
// reopen log file
sink->locked_backend()->rotate_file();

// ... do more logging

Я открываю файл журнала с std::ios_base::app чтобы предотвратить обрезание файла журнала, если файл существует.

Преимущество этого решения заключается в том, что копировать файлы не нужно, а записи журнала не будут ни потеряны, ни дублированы.

2

По вопросам рекламы [email protected]