I have developed an application (application1) that uses boost::log with severity_channel_logger_mt and two sinks (syslog_backend & text_file_backend).
When I run the application as an .exe, the sinks work fine and I am able to see log text files generate from messages being passed across a network, but when I link application1 as a .dll inside of another application (mainapp), I get the following errors after about 20 seconds:
Exception thrown at 0x00007FFA9E03CD29 in mainapp.exe: Microsoft C++ exception: boost::wrapexcept<boost::system::system_error> at memory location 0x000000F9BD9FF220.
Exception thrown at 0x00007FFA9E03CD29 in mainapp.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFA9E03CD29 in mainapp.exe: Microsoft C++ exception: boost::wrapexcept<boost::system::system_error> at memory location 0x000000F9BD9FF220.
Exception thrown at 0x00007FFA9E03CD29 in mainapp.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFA9E03CD29 in mainapp.exe: Microsoft C++ exception: boost::wrapexcept<boost::system::system_error> at memory location 0x000000F9BD9FF220.
Exception thrown at 0x00007FFA9E03CD29 in mainapp.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFA9E03CD29 in mainapp.exe: Microsoft C++ exception: boost::wrapexcept<boost::system::system_error> at memory location 0x000000F9BD9FF220.
After debugging, the exception happens in basic_sink_frontend.hpp and core.hpp between these two calls:
basic_sink_frontend.hpp
backend.consume(rec, context->m_FormattedRecord);
core.hpp
BOOST_FORCEINLINE void push_record(BOOST_RV_REF(record) rec)
{
push_record_move(static_cast< record& >(rec));
}
I have verified that the "rec" variable is not NULL. The application1 DLL loads wihout error and I am able to run application1 functions from mainapp. I still see message being passed across network from syslog sink, however text_file sink logs are not generated... I built boost as a shared library and have the following libs in boost_1_80_0/stage/lib: boost_log_setup-vc142-mt-x64-1_80 boost_log-vc142-mt-gd-x64-1_80 boost_log-vc142-mt-x64-1_80
Snippets from my code on how I use the loggers and sinks are below. Application1 uses boost::log and MainApp loads Application1 as DLL:
Application1:
#define DEFAULT_PORT 13000
#define DEFAULT_PORT_STRING "13000"
#define DEFAULT_IP "127.0.0.1"
enum class severity_levels
{
info,
warning,
error
};
void Application1::init_builtin_syslog()
{
// Create a syslog sink
boost::shared_ptr< sinks::synchronous_sink< sinks::syslog_backend > > sys_sink(
new sinks::synchronous_sink< sinks::syslog_backend >());
sys_sink->set_formatter
(
expr::stream << "Application 1 Log - ID: " << expr::attr< unsigned int >("RecordID")
<< "| " << expr::attr< severity_levels >("Severity") << ": " << expr::smessage
);
// We'll have to map our custom levels to the syslog levels
sinks::syslog::custom_severity_mapping< severity_levels > mapping("Severity");
mapping[severity_levels::info] = sinks::syslog::info;
mapping[severity_levels::warning] = sinks::syslog::warning;
mapping[severity_levels::error] = sinks::syslog::critical;
sys_sink->locked_backend()->set_severity_mapper(mapping);
#if !defined(BOOST_LOG_NO_ASIO)
// Set the remote address to send syslog messages to
sys_sink->locked_backend()->set_target_address(DEFAULT_IP, DEFAULT_PORT);
#endif
//Create a text file sink
boost::shared_ptr< sinks::synchronous_sink< sinks::text_file_backend > > file_sink(
new sinks::synchronous_sink< sinks::text_file_backend >(
keywords::file_name = "application1.log", // file name pattern
keywords::target_file_name = "application1_%Y%m%d_%H%M%S_%2N.log",
keywords::rotation_size = 16384
));
// Set up where the rotated files will be stored
file_sink->locked_backend()->set_file_collector(sinks::file::make_collector(
keywords::target = "logs",
keywords::max_size = 64 * 1024 * 1024,
keywords::min_free_space = 100 * 1024 * 1024,
keywords::max_files = 512
));
// Upon restart, scan the target directory for files matching the file_name pattern
file_sink->locked_backend()->scan_for_files();
file_sink->set_formatter
(
expr::format("%1% Application 1 Log - ID: %2% | %3% : \"%4%\"")
% expr::attr< boost::posix_time::ptime >("TimeStamp")
% expr::attr< unsigned int >("RecordID")
% expr::attr< severity_levels >("Severity")
% expr::smessage
);
// Add the sinks to the core
logging::core::get()->add_sink(sys_sink);
logging::core::get()->add_sink(file_sink);
// Add logging attributes
logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >());
logging::core::get()->add_global_attribute("TimeStamp", attrs::utc_clock());
}
int start()
{
init_builtin_syslog();
src::severity_channel_logger_mt\< severity_levels \> lg(keywords::severity = severity_levels::info, keywords::channel = "Application 1");
for (int i = 0; i \< 10000; ++i)
{
BOOST_LOG_SEV(lg, severity_levels::info) \<\< infoLog;
if(runexe) std::cout \<\< "App1 sent: " \<\< infoLog \<\< std::endl;
boost::this_thread::sleep_for(boost::chrono::milliseconds(1000));
}
return 0;
}
MainApp:
bool loadedApp1 = false;
std::atomic<bool> startApp1 = true;
std::atomic<char*> app1Err((char*)"");
HINSTANCE app1dll;
void printError( const TCHAR* msg );
typedef void (*MYPROC2)(std::atomic<bool>&, std::atomic<char*>&);
MYPROC2 app1start;
int main()
{
std::cout << "Starting application 1... " << std::endl;
try
{
app1dll = LoadLibrary(TEXT("application1.dll"));
if(app1dll == NULL)
{
std::cerr << "Application 1 DLL load library failure." << GetLastError() << '\n';
loadedApp1 = false;
}
else
{
loadedApp1 = true;
app1start = (MYPROC2) GetProcAddress(app1dll, MAKEINTRESOURCEA(1));
if (NULL != app1start)
{
std::thread t1(app1start, std::ref(startApp1), std::ref(app1Err));
t1.detach();
std::this_thread::sleep_for(std::chrono::milliseconds(4000));
}
if(startApp1.load() == false)
{
std::cout << "Error starting Application 1: " << app1Err.load() << std::endl;
}
}
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
return 1;
}
return 0;
}