我有一个作为服务运行很长时间的程序。我使用BOOST_LOG_TRIVIAL(info) << "Message"
来记录各种事件。我想与logrotate
合作,并在轮换后重新打开我的日志文件。从理论上讲,剧本的作用如下:
something.log
)或我手动将日志从something.log.1
重命名为logrotate
。something.log.1
文件。到目前为止我准备的例子(可能没有必要):
#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
Adam回答的源代码表示
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";
}
答案 0 :(得分:2)
我遇到了同样的问题并找到了一个非常简单的解决方案:只需用一个文件名(无任何模式)初始化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
打开日志文件,以防止在文件存在时截断日志文件。
此解决方案的优点是不需要复制任何文件,并且日志记录既不会丢失也不会重复。
答案 1 :(得分:1)
只需使用 copytruncate logrotate选项。
来自手册:
创建副本后,将原始日志文件截断 移动旧日志文件并可选择创建新日志文件。它可以 当一些程序无法被告知关闭其日志文件时使用 可能会继续永久写入(追加)到上一个日志文件。 请注意,复制文件之间的时间片非常小 并截断它,因此一些日志记录数据可能会丢失。当这个 使用选项,create选项将不起作用,作为旧日志 文件保持不变。
http://linux.die.net/man/8/logrotate
修改强>
试试这个。看一下 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