![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Logging sourcesBoost , Chapter 1. Boost.Log v2 , Detailed features description
|
![]() | Tip |
---|---|
По соображениям эффективности рекомендуется избегать динамической настройки названия канала индивидуально для каждой записи журнала, когда это возможно. Изменение названия канала предполагает выделение динамической памяти. Использование отдельных регистраторов для разных каналов позволяет избежать этих накладных расходов. |
#include <boost/log/sources/exception_handler_feature.hpp
>
Библиотека предоставляет функцию регистратора, которая позволяет пользователю обрабатывать и/или подавлять исключения на уровне регистратора. Функция<exception_handler
>добавляет метод<set_exception_handler
>к регистратору, который позволяет задать объект функции, который будет вызываться, если исключение выбрасывается из ядра регистрации во время фильтрации или обработки записей журнала. Можно использоватьбиблиотечные адаптерыдля упрощения реализации обработчиков исключений. Пример использования выглядит следующим образом:
enum severity_level { normal, warning, error }; // A logger class that allows to intercept exceptions and supports severity level class my_logger_mt : public src::basic_composite_logger< char, my_logger_mt, src::multi_thread_model< boost::shared_mutex >, src::features< src::severity< severity_level >, src::exception_handler > > { BOOST_LOG_FORWARD_LOGGER_MEMBERS(my_logger_mt) }; BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT(my_logger, my_logger_mt) { my_logger_mt lg; // Set up exception handler: all exceptions that occur while // logging through this logger, will be suppressed lg.set_exception_handler(logging::make_exception_suppressor()); return lg; } void logging_function() { // This will not throw BOOST_LOG_SEV(my_logger::get(), normal) << "Hello, world"; }
![]() | Tip |
---|---|
Ядро регистрацииифронтенды раковинытакже поддерживают установку обработчиков исключений. |
#include <boost/log/sources/severity_channel_logger.hpp
>
Если вам интересно, можете ли вы использовать смешанный набор из нескольких функций регистратора в одном регистраторе, то да, вы, безусловно, можете. Библиотека предоставляет<severity_channel_logger
>и<severity_channel_logger_mt
>(с их широкоугольными аналогами<wseverity_channel_logger
>и<wseverity_channel_logger_mt
>), которые сочетают в себе особенности описанных лесорубов суровнем строгостииканаламиподдержки. Композитные регистраторы также являются шаблонами, что позволяет указывать уровень серьезности и типы каналов. Вы также можете разработать свои собственные функции регистратора и объединить их с теми, которые предоставляются библиотекой, как описано в. Расширение библиотеки.
Использование лесозаготовителей с несколькими функциями концептуально не отличается от использования однофункциональных лесозаготовителей. Вот как можно использовать<severity_channel_logger_mt
>:
enum severity_level { normal, notification, warning, error, critical }; typedef src::severity_channel_logger_mt< severity_level, // the type of the severity level std::string // the type of the channel name > my_logger_mt; BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT(my_logger, my_logger_mt) { // Specify the channel name on construction, similarly as with the channel_logger return my_logger_mt(keywords::channel = "my_logger"); } void logging_function() { // Do logging with the severity level. The record will have both // the severity level and the channel name attached. BOOST_LOG_SEV(my_logger::get(), normal) << "Hello, world!"; }
#include <boost/log/sources/global_logger_storage.hpp
>
Иногда неудобно иметь объект регистратора, чтобы иметь возможность писать журналы. Эта проблема часто присутствует в коде функционального стиля без очевидных мест, где можно хранить регистратор. Другой областью, где проблема сохраняется, являются общие библиотеки, которые выиграют от регистрации. В таких случаях было бы удобнее иметь одного или нескольких глобальных регистраторов, чтобы при необходимости легко получить к ним доступ в любом месте. В этом отношении<std::cout
>является хорошим примером такого лесозаготовителя.
Библиотека предоставляет способ декларирования глобальных регистраторов, к которым можно получить доступ почти как<std::cout
>. Фактически, эта функция может быть использована с любым регистратором, включая пользовательские. Объявив глобальный регистратор, можно быть уверенным, что у вас есть безопасный доступ к этому регистратору из любого места кода приложения. Библиотека также гарантирует, что глобальный регистратор будет уникальным даже за пределами модулей. Это позволяет использовать журналирование даже в компонентах только для заголовков, которые могут быть скомпилированы в различные модули.
Можно задаться вопросом, зачем нужно что-то особенное для создания глобальных лесозаготовителей. Почему бы просто не объявить переменную регистратора в области пространства имен и использовать ее везде, где вам нужно? Хотя технически это возможно, декларирование и использование глобальных переменных лесозаготовителей затруднено по следующим причинам:
main
>).a
>имеет внешнюю связь и была скомпилирована в модули X и Y, каждый из этих модулей имеет свою копию переменной<a
>. Что еще хуже, на других платформах эта переменная может быть разделена между модулями.Глобальное хранение лесозаготовителей призвано устранить все эти проблемы.
Самый простой способ объявить глобального регистратора - использовать следующий макрос:
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT
(my_logger, src::severity_logger_mt< >)
<my_logger
>Аргумент дает регистратору имя, которое может быть использовано для приобретения регистратора. Это имя действует как метка объявленного лесоруба. Второй параметр обозначает тип лесозаготовителя. В многопоточных приложениях, когда к регистратору можно получить доступ из разных потоков, пользователи обычно хотят использовать безопасные для потоков версии регистраторов.
Если требуется передача аргументов конструктору регистратора, есть еще один макрос:
BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS
(
my_logger,
src::severity_channel_logger< >,
(keywords::severity = error)(keywords::channel = "my_channel"))
Последний макроаргумент — этоBoost.Preprocessorпоследовательность аргументов, переданная конструктору регистратора. Однако будьте осторожны при использовании непостоянных выражений и ссылок на объекты в качестве аргументов конструктора, так как аргументы оцениваются только один раз и часто трудно сказать точный момент, когда это сделано. Лесоруб строится по первому запросу из любой части заявки, которая знает декларацию лесозаготовителя. Пользователь должен убедиться, что все аргументы имеют действительные состояния.
Третий макрос этого раздела обеспечивает максимальную гибкость инициализации, позволяя пользователю фактически определить логику создания регистратора.
BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT
(my_logger, src::severity_logger_mt)
{
// Do something that needs to be done on logger initialization,
// e.g. add a stop watch attribute.
src::severity_logger_mt< > lg;
lg.add_attribute("StopWatch", boost::make_shared< attrs::timer >());
// The initializing routine must return the logger instance
return lg;
}
Как и макрос<BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS
>, код инициализации называется только один раз, по первому требованию регистратора.
![]() | Important |
---|---|
Остерегайтесь правил одного определения (ODR). Независимо от выбранного вами способа декларирования регистратора, вы должны убедиться, чторегистратор объявлен точно таким же образом во всех случаяхивсе имена символов, участвующие в декларации, разрешают одинаковые объекты. Последнее включает в себя имена, используемые в рутине инициализации макроса< |
Для решения проблем, связанных с ODR, можно отделить декларацию лесозаготовителя и процедуру ее инициализации. Библиотека предоставляет следующие макросы для достижения этой цели:
BOOST_LOG_GLOBAL_LOGGER
>Пояснительная записка. Он может использоваться в заголовке, аналогично<BOOST_LOG_INLINE_GLOBAL_LOGGER*
>макросам, описанным выше.BOOST_LOG_GLOBAL_LOGGER_INIT
>,<BOOST_LOG_GLOBAL_LOGGER_DEFAULT
>и<BOOST_LOG_GLOBAL_LOGGER_CTOR_ARGS
>определяют порядок инициализации регистратора. Их семантика и использование аналогичны соответствующим<BOOST_LOG_INLINE_GLOBAL_LOGGER*
>макросам, за одним исключением: эти макросы должны использоваться в одном файле .cpp.Например:
// my_logger.h // =========== BOOST_LOG_GLOBAL_LOGGER(my_logger, src::severity_logger_mt) // my_logger.cpp // =========== #include "my_logger.h" BOOST_LOG_GLOBAL_LOGGER_INIT(my_logger, src::severity_logger_mt) { src::severity_logger_mt< > lg; lg.add_attribute("StopWatch", boost::make_shared< attrs::timer >()); return lg; }
Независимо от макроса, который вы использовали для объявления регистратора, вы можете получить экземпляр регистратора со статической функцией<get
>тега регистратора:
src::severity_logger_mt< >& lg = my_logger::get();
Дальнейшее использование регистратора такое же, как если бы он был обычным объектом регистратора соответствующего типа.
![]() | Warning |
---|---|
Следует отметить, что на этапе деинициализации заявки не рекомендуется использовать глобальные лесозаготовители. Как и любой другой глобальный объект в вашем приложении, глобальный регистратор может быть уничтожен, прежде чем вы попытаетесь его использовать. В таких случаях лучше иметь выделенный объект регистратора, который гарантированно будет доступен столько, сколько необходимо. |
Статья Logging sources раздела Chapter 1. Boost.Log v2 Detailed features description может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: Detailed features description ::
реклама |