I have successfully created a class that uses a global boost logger (supporting multi-threaded and severity level) which is created in the class's header file. I want to log different messages to different files along the same lines as this answer 39247778. This implementation works as expected.
CC2Logger.h:
BOOST_LOG_ATTRIBUTE_KEYWORD(tag_attr, "Tag", std::string);
static sources::severity_logger_mt<logging::trivial::severity_level> GLOBAL_C2LOGGER;
class CC2Logger {
public:
CC2Logger(const std::string& folderName = "logs/", const std::string& fileBaseName = "LOG_", const std::string& fileExtName = ".log");
void log(logging::trivial::severity_level logMessageLevel, const std::string& logMessage);
void log(logging::trivial::severity_level logMessageLevel, const std::stringstream& logMessage);
private:
const std::string m_tag;
const std::string m_folderName;
const std::string m_fileBaseName;
const std::string m_fileExtName;
};
CC2Logger.cc:
#include "CC2Logger.h"
CC2Logger::CC2Logger(const std::string& folderName, const std::string& fileBaseName, const std::string& fileExtName) :
m_folderName(folderName), m_fileBaseName(fileBaseName), m_fileExtName(fileExtName), m_tag(fileBaseName) {
auto sink = logging::add_file_log(keywords::target = m_folderName,
keywords::file_name = m_fileBaseName + "_%Y%m%d-%H%M%S-%4N" + m_fileExtName,
keywords::rotation_size = ROTATE_FILE_AFTER_NUM_BYTES);
sink->set_formatter(logging::parse_formatter(GLOBAL_C2LOGGER_LOGFMT_STRING));
sink->set_filter(tag_attr == m_tag);
}
void CC2Logger::log(logging::trivial::severity_level logMessageLevel, const std::string& logMessage) {
BOOST_LOG_SCOPED_THREAD_TAG("Tag", m_tag);
BOOST_LOG_SEV(GLOBAL_C2LOGGER, logMessageLevel) << logMessage;
}
void CC2Logger::log(logging::trivial::severity_level logMessageLevel, const std::stringstream& logMessage) {
BOOST_LOG_SCOPED_THREAD_TAG("Tag", m_tag);
const std::string logMessage_str = logMessage.str();
BOOST_LOG_SEV(GLOBAL_C2LOGGER, logMessageLevel) << logMessage_str;
}
Now, instead of using the global logger instantiated in the header file (GLOBAL_C2LOGGER), I want to pass in the logger to the CC2Logger class's ctor and assign it to a member variable (e.g. m_ptrLogger) during instantiation of the class, such as:
int main(int argc, char* argv[]) {
logging::add_common_attributes();
logging::register_simple_formatter_factory<logging::trivial::severity_level, char>("Severity);
boost::shared_ptr<sources::severity_logger_mt<logging::trivial::severity_level>> a_logger;
boost::shared_ptr<sources::severity_logger_mt<logging::trivial::severity_level>> b_logger;
CC2Logger CTestLogger_A(a_logger, "logs/", "LOG_aA", ".log");
CC2Logger CTestLogger_B(a_logger, "logs/", "LOG_aB", ".log");
CC2Logger CTestLogger_C(b_logger, "logs/", "LOG_bC", ".log");
CTestLogger_A.log(logger::trivial::trace, "A simple trace message to file LOG_aA...log using a_logger.");
CTestLogger_A.log(logger::trivial::info, "A simple info message to file LOG_aA...log also using a_logger.");
CTestLogger_C.log(logger::trivial::info, "A simple info message to file LOG_bC...log using b_logger.");
return 0;
}
I have tried adding a member variable to CC2Logger.h that is a boost::shared_ptr< sources::severity_logger_mt<logging::trivial::severity_level> > m_ptrLogger; then pass that into the CC2Logger::CC2Logger ctor by reference as &ptrLogger (of same boost::shared_ptr<...> type) but to no avail. I have tried a lot of syntax variations like m_ptrLogger.reset(<variations>), tried to use the ctor initializer lists, but nothing seems to work. Didn't want to clutter things with all the things I tried.
I am apparently not passing the boost_shared pointer correctly, not using it correctly in the BOOST_LOG_SEV macros, or totally missed the boat.
First, you don't need to store a
shared_ptrto a logger as a member of your class. You can store the logger itself. The logger is copyable, moveable and default-constructible, so it will not constrain your class capabilities. You only need ashared_ptrif you specifically want multiple instances of your class to share a common logger object for some reason (which you haven't described in the question).Second, you don't need to pass the logger from the caller and can create the logger object in your class' constructor. You only need to pass the required constructor parameters to the logger to initialize its default tag. The logger constructor accepts named parameters.
Third, instead of using a custom tag attribute to differentiate between records made through different loggers, you can use channels, which are essentially the same thing, only provided by the library out of the box. Channels and severity levels are different logger features that can be combined and used together in one logger type. This means the logger will emit log records that have both the severity level and the channel name attached.
So, with these suggestions combined, the code could look something like this:
PS: If you're having a problem with initializing and passing a
shared_ptrinstead then please post it as a separate question that is not related to Boost.Log.