Reputation: 3625
I am using Boost for storing logs in files. Everything is fine, the rotation works, but is there a possibility to rotate the logs in just two files? I would like to have just two files of maximum 250 MB size and if one is filled, then it stores the logs in the other file ad if the second is filled, then the first one is going to be cleaned and the new logs are going to be stored there... and so on. Is it possible via Boost?
I have see that there is a sink->locked_backend()->set_close_handler(&foo);
, isn't there a possibility to use that function to delete the old log file? (Until now I have not managed to find it)
Upvotes: 1
Views: 1519
Reputation: 3625
I have implementer a way of deleting the oldest file when creating the third one.
I have created the following class:
class Tutorial
{
public:
enum SeverityLevels
{
debugs,
infos,
warnings,
errors
};
static void initFilesList()
{
fs::path path("../logs/");
fs::directory_iterator endDir;
if (!fs::exists(path))
{
return;
}
if (!fs::is_directory(path))
{
return;
}
for (fs::directory_iterator it(path); it != endDir; it++)
{
if (fs::is_regular_file(it->status()))
{
if (fs::extension(*it) == ".log")
{
std::string fileToPush = it->path().string();
if (std::find(sm_queue.begin(), sm_queue.end(), fileToPush) == sm_queue.end())
{
sm_queue.push_back(fileToPush);
while (sm_queue.size() > 2)
{
std::string fileToDelete = sm_queue.front();
if (fs::exists(fs::path(fileToDelete)))
{
fs::remove(fs::path(fileToDelete));
sm_queue.pop_front();
}
else
{
throw NoSuchFileException(fileToDelete);
}
}
}
}
else
{
throw BadExtensionLogException(it->path().string());
}
}
}
}
private:
static std::list< std::string > sm_queue;
std::size_t m_cntr;
src::severity_logger< SeverityLevels > m_slg;
/** The function initializes the logging to mentioned file and with specific format and rotation
*
* @param fileNameIn : input file name string
*/
void initZZ()
{
boost::shared_ptr< sinks::synchronous_sink< sinks::text_file_backend > > sink = logging::add_file_log(
"../logs/" + m_logFileName + "_%N.log",
keywords::format = expr::stream
<< expr::attr< attrs::current_process_name::value_type >("Executable") << "("
<< expr::attr< attrs::current_process_id::value_type >("ExeUID") << ") CID(" << line_id << ") " << severity
<< "[" << expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S.%f") << "] ["
<< expr::attr< attrs::current_thread_id::value_type >("ThreadID") << "] " << scope << " - " << expr::smessage,
keywords::open_mode = (std::ios::out | std::ios::app),
keywords::rotation_size = 25 * 1024
);
sink->locked_backend()->set_open_handler(&Tutorial::openingHandler);
logging::core::get()->set_filter(severity >= SeverityLevels::infos);
logging::core::get()->add_sink(sink);
}
static void openingHandler(sinks::text_file_backend::stream_type& file)
{
initFilesList()
}
public:
Tutorial(const std::string& fileNameIn) : m_cntr(0), m_logFileName(fileNameIn)
{
initZZ();
}
/** The function writes logs on the mentioned file and with the mentioned format with rotating on size
*
* @param fileNameIn : input filen name string
*/
void zzLoggingFormattedToFile()
{
BOOST_LOG_SEV(m_slg, SeverityLevels::debugs) << "Debug message " << m_cntr;
BOOST_LOG_SEV(m_slg, SeverityLevels::errors) << "Error message " << m_cntr;
BOOST_LOG_SEV(m_slg, SeverityLevels::infos) << "Info message " << m_cntr;
BOOST_LOG_SEV(m_slg, SeverityLevels::warnings) << "Warning message " << m_cntr;
++m_cntr;
}
};
and the following overload of operator<<
:
/** The operator used for SeverityLevels */
std::ostream& operator<< (std::ostream& strmIn, Tutorial::SeverityLevels levelIn)
{
static const char* stringsLevels[] =
{
"DEBG",
"INFO",
"WARN",
"ERRR"
};
if (static_cast< std::size_t >(levelIn) < sizeof(stringsLevels) / sizeof(*stringsLevels))
{
strmIn << stringsLevels[levelIn];
}
else
{
strmIn << static_cast< int >(levelIn);
}
return strmIn;
}
So this way each time a new log file is created it is done a scan of log files and if there are more than 2 the oldest is deleted. The names of the files are kept in a list and each time is deleted the first that was inserted in.
I would like any remark; What do you think about it?
I know that there may be a bug of not deleting the last log file, if the application has run before more than once and there are files in the logs folder: the case is when there are log_0.log
- from last run - and log_X.log
- from the run before last; this way the first inserted in the list will be log_0.log
, but this could be fixed by adding date and hour instead of counter.
Upvotes: 1
Reputation: 393114
Interesting question.
It looks like the boost devs have decided this is easier to implement as a separate garbage collect if you will
rm -v $(ls -t mylog_*.log | tail -n -2)
Upvotes: 1