У меня есть исполняемый файл как для Linux, так и для Windows с тремя DLL/разделяемыми библиотеками, и я использую boost.log для ведения журнала. Я хочу иметь отдельный файл для каждого модуля. Мой подход заключался в создании severity_channel_logger_mt для каждого модуля, построенного в одноэлементном режиме для каждого модуля с именем канала.усиление фильтрации канала регистрации в разделяемых библиотеках не работает как ожидалось на linux
class LogSingleton final
{
src::severity_channel_logger_mt<logging::trivial::severity_level, std::string> slg_;
...
protected:
LogSingleton() : slg_(boost::log::keywords::channel = "ModuleOne") {}
public:
src::severity_channel_logger_mt<logging::trivial::severity_level, std::string>& logger() { return slg_; }
...
};
Каждый модуль затем создает свой собственный радиатор файла по инициализации и устанавливает фильтр канала, чтобы сообщения журнала только тот модуль должны достичь этой раковины.
logging::add_file_log(logging::keywords::file_name = "module_one.log",
logging::keywords::open_mode = std::ios::app,
->set_filter(logging::trivial::severity >= level
&& expr::attr<std::string>("Channel") == "ModuleOne");
Я создал собственный макрос конкретного модуля для ведения журнала, который переходит к правильному регистратору.
#define BLOG(lvl) BOOST_LOG_STREAM_WITH_PARAMS((LogSingleton::instance()->logger()), (::boost::log::keywords::severity = ::boost::log::trivial::lvl))
, который используется, как это:
BLOG(info) << "Hello world";
Хотя на лесозаготовительных работах Windows, как и ожидалось, на Linux файлы журнала для ModuleOne (инициализируется первый) и ModuleThree (инициализирован третий) не получают журнал Сообщения. ModuleTwo работает правильно. Код регистрации для всех трех модулей идентичен, кроме имени файла журнала, имен каналов и имени класса singleton.
Я задаюсь вопросом, есть ли проблема с моим макросом, но любые идеи приветствуются вместе с комментариями к подходу.
Update
я сократил эту проблему до минимального, например, все в одном исполняемом файле. Проблема с общей библиотекой была неправильной. Проблема заключается в том, что если я создам файл severity_channel_logger в одноэлементном режиме, регистрация завершится с ошибкой. Если я использую локальный регистратор, работает журнал. Даже если я создаю регистратор в одноэлементном режиме и не использую его, он запрещает работу локального регистратора. Несмотря на прослеживание кода, я не понимаю, почему это происходит. (Платформа = Fedora 21, GCC 4.9.2, форсирует 1.58)
#include <boost/config.hpp>
#include <boost/filesystem.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/sources/severity_feature.hpp>
#include <boost/log/sources/severity_channel_logger.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/expressions/formatters/date_time.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/attributes/current_thread_id.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
namespace logging = boost::log;
namespace expr = boost::log::expressions;
namespace src = boost::log::sources;
namespace fs = boost::filesystem;
class LogSingleton
{
src::severity_channel_logger<logging::trivial::severity_level, std::string> slg_;
static LogSingleton* instance_;
LogSingleton(const LogSingleton&);
LogSingleton& operator=(const LogSingleton&);
protected:
LogSingleton() : slg_(boost::log::keywords::channel = "Core") {}
public:
src::severity_channel_logger<logging::trivial::severity_level, std::string>& logger()
{
return slg_;
}
static LogSingleton* instance()
{
if (!instance_)
{
instance_ = new LogSingleton;
}
return instance_;
}
};
LogSingleton* LogSingleton::instance_ = nullptr;
// 1. doesn't work
//#define BLOG(lvl) BOOST_LOG_STREAM_WITH_PARAMS((LogSingleton::instance()->logger()), (::boost::log::keywords::severity = ::boost::log::trivial::lvl))
// access to logger via reference. Works if it is passed a ref to logger declared in main. Doesn't work if it is ref to logger in singleton
#define BLOG(lvl) BOOST_LOG_STREAM_WITH_PARAMS((rlogger), (::boost::log::keywords::severity = ::boost::log::trivial::lvl))
int main(int argc, char **argv)
{
logging::add_common_attributes();
logging::trivial::severity_level level = logging::trivial::trace;
auto formatter = expr::stream
<< "[" << expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%dT%H:%M:%S.%f")
<< "] (" << logging::trivial::severity
<< "): " << expr::message;
fs::path plog = fs::system_complete(fs::path(".."));
if (!fs::exists(plog) || !fs::is_directory(plog))
throw std::invalid_argument("Log directory doesn't exist, or path isn't a directory");
plog /= "core.log";
logging::add_file_log(logging::keywords::file_name = plog.string(),
logging::keywords::open_mode = std::ios::app,
logging::keywords::format = formatter)
->set_filter(logging::trivial::severity >= level && expr::attr<std::string>("Channel") == "Core");
// this works with rlogger macro variant
src::severity_channel_logger<logging::trivial::severity_level, std::string> logger(boost::log::keywords::channel = "Core");
auto& rlogger = logger;
// 2. this doesn't work, with same macro
//auto& rlogger = LogSingleton::instance()->logger();
// 3. just creating the singleton, before or after the creation of the local logger, stops logging from working
//LogSingleton::instance();
BLOG(info) << "Hello world";
return 0;
}
В настоящее время написано, этот пример работает с местным регистратором. Комментарий с меткой 1 - это вариант макроса, который использует singleton logger direct (fail). Кроме того, комментирует местный регистратор и дает ссылку на синглтон. (комментарий 2). Комментарий, отмеченный 3, показывает, что просто создание одноточечного регистратора приводит к сбою регистрации в логгере.
Немного больше деталей. Я не могу использовать один глобальный регистратор в Windows, поскольку они не разделяются между разными dll, если они определены в одном из них (единственное место, где я контролирую). Кроме того, добавление канала в макрос не изменяет поведение, как в '#define BLOG (lvl) BOOST_LOG_STREAM_WITH_PARAMS ((LogSingleton :: instance() -> logger()), (:: boost :: log :: keywords :: channel = "ModuleOne") (:: boost :: log :: keywords :: severity = :: boost :: log :: trivial :: lvl)) ' – nostep