How can I use Boost.Log across DLL boundaries?

2019-04-25 12:11发布

问题:

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.

Approach 1

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).

Approach 2

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?

回答1:

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.



回答2:

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.



回答3:

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.