I am trying to integrate Boost.Log in a fairly large application that is composed of a main application that dynamically loads plugins from DLLs. The initial idea was to pass a logging source to plugins so that they can add log messages. However, as soon as code from a DLL tries to log a message to the provided source, the application crashes with an access violation.
The following minimal example illustrates the problem:
int main(int argc, char* argv[])
{
boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> logger;
// This is okay
BOOST_LOG_SEV(logger, boost::log::trivial::info) << "From main()";
// This crashes
logFromDll(logger);
return 0;
}
Where logFromDll
is defined in a separate (DLL) project:
Dll.cpp
TESTDLL_API void logFromDll(boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> &logger)
{
BOOST_LOG_SEV(logger, boost::log::trivial::info) << "From dll";
}
As stated above, this crashes with an access violation in logFromDll
(compiled with visual studio 2010).
Boost.Log provides a mechanism for "global storage" of logging sources:
Having declared a global logger, one can be sure to have a thread-safe access to this logger instance from any place of the application code. The library also guarantees that a global logger instance will be unique even across module boundaries.
Sounds exactly like what I need. So I set up the following example:
Logger.h
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level>)
Main.cpp
int main(int argc, char* argv[])
{
boost::log::add_console_log
(
std::clog,
boost::log::keywords::format =
(
boost::log::expressions::stream << "[Custom format] " << boost::log::expressions::smessage
)
);
BOOST_LOG_SEV(my_logger::get(), boost::log::trivial::info) << "From main()";
logFromDll();
return 0;
}
Dll.cpp
TESTDLL_API void logFromDll()
{
BOOST_LOG_SEV(my_logger::get(), boost::log::trivial::info) << "From dll";
}
This does not crash, but yields the following output:
[Custom format] From main()
[2014-06-19 10:22:28.435366] [0x00000233] [info] From dll
That is, the custom formatting that I set up in main.cpp is only applied when I log from the main project. Any logging from the DLL project is formatted using the default format.
So, how can I perform logging across DLL boundaries in a way that all (formatting) options I set up in the main project are applied correctly?
I've figured out what the problem was. The documentation for Boost.Log states that:
If your application consists of more than one module (e.g. an exe and one or several dll's) that use Boost.Log, the library must be built as a shared object. If you have a single executable or a single module that works with Boost.Log, you may build the library as a static library.
I was using Boost.Log as a static library. Building boost with shared linkage and using that in my project resolved the problem.
Not really an answer directly to your question
Personally I think you are asking the DLL to do too much. In general my approach logging from DLLs has been to remove the logging peculiarities to the application by providing a simple callback function to the DLL.
Usually the form some variant of:
std::function<void (DLL::LogLevel, const char*, ...)> logFunc;
It's up to the application to provide a correct translation to its own service.
To have completed solution just add #define BOOST_LOG_DYN_LINK
into described logger.h
before BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT
and include logger.h
into application/dll source files.
User contributions licensed under CC BY-SA 3.0