Using Boost log for logging purposes (duh) - and I am successful in initialization:
BOOST_LOG_GLOBAL_LOGGER_INIT(logger, logger_t) {
logger_t lg;
logging::add_common_attributes();
boost::shared_ptr< file_sink > sink(new file_sink(
boost::log::keywords::file_name = "appLog_%N.log",
boost::log::keywords::rotation_size = 2 * 1024 * 1024,
boost::log::keywords::max_size = 10 * 1024 * 1024,
boost::log::keywords::scan_method =
boost::log::sinks::file::scan_method::scan_matching,
boost::log::keywords::open_mode = std::ios_base::app,
boost::log::keywords::auto_flush = true
));
sink->set_formatter(
expr::stream
<< expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%dT%H:%M:%S.%fz")
<< ": [" << logging::trivial::severity
<< "]\t" << expr::smessage
);
sink->locked_backend()->set_file_collector(boost::log::sinks::file::make_collector(
boost::log::keywords::target = "", /*< the target directory >*/
boost::log::keywords::max_size = 10 * 1024 * 1024, /*< maximum total size of the stored files, in bytes >*/
boost::log::keywords::min_free_space = 1 * 1024 * 1024, /*< minimum free space on the drive, in bytes >*/
boost::log::keywords::max_files = 10 /*< maximum number of stored files >*/
));
sink->locked_backend()->scan_for_files(boost::log::sinks::file::scan_method::scan_matching, true);
logging::core::get()->add_sink(sink);
logging::core::get()->set_filter
(
logging::trivial::severity >= logging::trivial::info
);
return lg;
}
However, after reading in and processing the application's configuration file, which includes values specifying rotation_size and max_size for logging, I am having difficulty removing all sinks, before creating a new sink with the specified values for rotation_size and max_size simply adds a sink on top of the existing sink which was initialized globally (which results in each message being logged twice).
The function for updating the sizes of the log is as follows:
void setLoggerSizes(int rotationSize, int maxSize)
{
//INFO << "";
logging::core::get()->remove_all_sinks();
logging::add_common_attributes();
boost::shared_ptr< file_sink > sink(new file_sink(
boost::log::keywords::file_name = "appLog_%N.log",
boost::log::keywords::rotation_size = rotationSize * 1024 * 1024,
boost::log::keywords::max_size = maxSize * 1024 * 1024,
boost::log::keywords::scan_method = boost::log::sinks::file::scan_method::scan_matching,
boost::log::keywords::open_mode = std::ios_base::app,
boost::log::keywords::auto_flush = true
));
sink->set_formatter(
expr::stream
<< expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%dT%H:%M:%S.%fz")
<< ": [" << logging::trivial::severity
<< "]\t" << expr::smessage
);
sink->locked_backend()->set_file_collector(
boost::log::sinks::file::make_collector(
boost::log::keywords::target = "",
boost::log::keywords::max_size = maxSize * 1024 * 1024,
boost::log::keywords::min_free_space = 1 * 1024 * 1024
)
);
sink->locked_backend()->scan_for_files();
logging::core::get()->add_sink(sink);
}
Yet, if I add the INFO << "";
in within the beginning of the function, this seems to force the removal of all sinks and when adding the sink with the correct file sizes, results in a single sink (and consequently only one copy of messages to be passed to the log).
Thus, my questions are:
INFO << "";
? It does not make any logical sense as to why adding that line would truly force a removal of all sinks which is called in the next line - and consequently result in a single copy of messages to be logged. Whereas, not including the INFO line, it is like the logging::core::get()->remove_all_sinks();
call is ignored, and the sink which is added with the correct file sizes is added on top of the initialized sink, and results in two copies of each message to be logged.For reference, this is the Logger.h file:
#pragma once
#include <boost/log/expressions.hpp>
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup.hpp>
#define FATAL BOOST_LOG_SEV(logger::get(), boost::log::trivial::fatal)
#define WARNING BOOST_LOG_SEV(logger::get(), boost::log::trivial::warning)
#define INFO BOOST_LOG_SEV(logger::get(), boost::log::trivial::info)
#define DEBUG BOOST_LOG_SEV(logger::get(), boost::log::trivial::debug)
#define TRACE BOOST_LOG_SEV(logger::get(), boost::log::trivial::trace)
typedef boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> logger_t;
typedef boost::log::sinks::synchronous_sink< boost::log::sinks::text_file_backend > file_sink;
BOOST_LOG_GLOBAL_LOGGER(logger, logger_t)
void setLoggerSizes(int rotationSize, int maxSize);
The problem you're seeing is most likely because of the order of the execution of the logging statements in your program.
The body of the BOOST_LOG_GLOBAL_LOGGER_INIT
and the similar BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT
macro is executed once, when the global logger is requested by the program for the very first time (see here). So, since you request the logger from within your INFO
macro, that body is executed before you call remove_all_sinks
and further initialize the logging library. When you comment that line, that initialization is deferred until your first executed logging statement, which, presumably, happens after setLoggerSizes
returns. Hence, remove_all_sinks
has no effect since there are no sinks to remove at the point of that call.
The _INIT
macros are really intended to initialize the logger, not the whole logging library (i.e. sinks, filters and what not). You can initialize the library from those macros, but, as you've found out, the usefullness of this is fairly limited (basically, it will likely not work as intended unless you have a single global logger, which is also the only logger you use in your whole application, and you don't need to update the logging configuration once it is initialized). The correct way to do this is to initialize the logging library separately in a function that you will call some time early in your main
, and use _INIT
macros to only initialize loggers.