![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Sink frontendsBoost , Chapter 1. Boost.Log v2 , Detailed features description
|
![]() | Note |
---|---|
Как и ядро регистрации, все фронтенды раковины предполагают, что безопасно вызывать фильтры из нескольких потоков одновременно. Это хорошо с библиотечными фильтрами. |
Для текстовых панелей раковины frontends реализуют форматирование записей. Как и фильтры, лямбда-выражениямогут использоваться для создания формататоров. Формататор может быть установлен для текстовой раковины, позвонив по<set_formatter
>методу или очистить, позвонив<reset_formatter
>.
Все фронтенды раковины позволяют настраивать обработчики исключений, чтобы настроить обработку ошибок на основе per-sink. Можно установить функцию обработки исключений с помощью метода<set_exception_handler
>, эта функция будет вызываться без аргументов из блока<catch
>, если исключение происходит во время обработки записей в бэкэнде или во время фильтрации, характерной для раковины. Обработчик исключений свободен отбросить исключение или подавить его. В первом случае исключение распространяется на ядро, где в действие может вступить другой уровень обработки исключений.
![]() | Tip |
---|---|
Ядро регистрацииирегистраторытакже поддерживают установку обработчиков исключений. |
Библиотека предоставляетудобный инструментдля отправки исключений в унарный полиморфный функциональный объект.
![]() | Note |
---|---|
Обработчику исключений не разрешается возвращать стоимость. Это означает, что вы не сможете изменить результат фильтрации, как только произойдет исключение, и, таким образом, фильтрация всегда выйдет из строя. |
![]() | Note |
---|---|
Все фронтенды раковины предполагают, что безопасно вызывать обработчиков исключений из нескольких потоков одновременно. Это хорошо для диспетчеров исключений, предоставляемых библиотекой. |
#include <boost/log/sinks/unlocked_frontend.hpp
>
Разблокированный интерфейс раковины реализован с шаблоном класса<unlocked_sink
>. Этот frontend предоставляет самый базовый сервис для backend.<unlocked_sink
>frontend не выполняет синхронизацию потоков при доступе к backend, предполагая, что синхронизация либо не нужна, либо реализована backend. Тем не менее, настройка фильтра по-прежнему безвредна (то есть можно безопасно изменить фильтр в<unlocked_sink
>интерфейсе, в то время как другие потоки записывают журналы через эту раковину). Это единственный фронтенд раковины, доступный в одной резьбовой среде. Пример использования заключается в следующем:
enum severity_level { normal, warning, error }; // A trivial sink backend that requires no thread synchronization class my_backend : public sinks::basic_sink_backend< sinks::concurrent_feeding > { public: // The function is called for every log record to be written to log void consume(logging::record_view const& rec) { // We skip the actual synchronization code for brevity std::cout << rec[expr::smessage] << std::endl; } }; // Complete sink type typedef sinks::unlocked_sink< my_backend > sink_t; void init_logging() { boost::shared_ptr< logging::core > core = logging::core::get(); // The simplest way, the backend is default-constructed boost::shared_ptr< sink_t > sink1(new sink_t()); core->add_sink(sink1); // One can construct backend separately and pass it to the frontend boost::shared_ptr< my_backend > backend(new my_backend()); boost::shared_ptr< sink_t > sink2(new sink_t(backend)); core->add_sink(sink2); // You can manage filtering through the sink interface sink1->set_filter(expr::attr< severity_level >("Severity") >= warning); sink2->set_filter(expr::attr< std::string >("Channel") == "net"); }
Все оконные бэкэнды, предоставляемые библиотекой, требуют синхронизации потоков на интерфейсной части. Если бы мы попытались создать интерфейс на бэкэнде, который требует более строгих гарантий потоков, чем то, что обеспечивает интерфейс, код не был бы собран. Поэтому этот интерфейс в основном полезен в однопоточной среде и с пользовательскими бэкэндами.
#include <boost/log/sinks/sync_frontend.hpp
>
Синхронный интерфейс раковины реализован с шаблоном класса<synchronous_sink
>. Он похож на<unlocked_sink
>, но дополнительно обеспечивает синхронизацию потоков с mutex перед передачей записей журнала на бэкэнд. Все нисходящие бэкэнды, поддерживающие форматирование, в настоящее время требуют синхронизации потоков в интерфейсе.
Синхронная раковина также вводит возможность получения указателя на заблокированный бэкэнд. Пока указатель существует, бэкэнд гарантированно не будет доступен из других потоков, если доступ не осуществляется через другой интерфейс или прямую ссылку на бэкэнд. Эта функция может быть полезна, если есть необходимость выполнить некоторые обновления на задней панели раковины, в то время как другие потоки могут записывать журналы. Однако остерегайтесь, что в то время как бэкэнд заблокирован, любая другая нить, которая пытается написать запись журнала в раковину, блокируется до тех пор, пока бэкэнд не будет выпущен.
Схожая ситуация с<unlocked_sink
>.
enum severity_level { normal, warning, error }; // Complete sink type typedef sinks::synchronous_sink< sinks::text_ostream_backend > sink_t; void init_logging() { boost::shared_ptr< logging::core > core = logging::core::get(); // Create a backend and initialize it with a stream boost::shared_ptr< sinks::text_ostream_backend > backend = boost::make_shared< sinks::text_ostream_backend >(); backend->add_stream( boost::shared_ptr< std::ostream >(&std::clog, boost::null_deleter())); // Wrap it into the frontend and register in the core boost::shared_ptr< sink_t > sink(new sink_t(backend)); core->add_sink(sink); // You can manage filtering and formatting through the sink interface sink->set_filter(expr::attr< severity_level >("Severity") >= warning); sink->set_formatter ( expr::stream << "Level: " << expr::attr< severity_level >("Severity") << " Message: " << expr::smessage ); // You can also manage backend in a thread-safe manner { sink_t::locked_backend_ptr p = sink->locked_backend(); p->add_stream(boost::make_shared< std::ofstream >("sample.log")); } // the backend gets released here }
#include <boost/log/sinks/async_frontend.hpp
> // Related headers #include <boost/log/sinks/unbounded_fifo_queue.hpp
> #include <boost/log/sinks/unbounded_ordering_queue.hpp
> #include <boost/log/sinks/bounded_fifo_queue.hpp
> #include <boost/log/sinks/bounded_ordering_queue.hpp
> #include <boost/log/sinks/drop_on_overflow.hpp
> #include <boost/log/sinks/block_on_overflow.hpp
>
Фронтенд реализован в шаблоне класса<asynchronous_sink
>. Как и синхронная, асинхронная раковина обеспечивает способ синхронизации доступа к бэкэнду. Все записи журнала передаются на бэкэнд в выделенном потоке, что делает его подходящим для бэкэндов, которые могут блокироваться в течение значительного количества времени (например, сетевые и другие аппаратные устройства, связанные с раковинами). Внутренняя нить фронтенда нерестится на фронтенд-конструкторе и присоединяется к его деструктору (что означает, что фронтенд-разрушение может блокироваться).
![]() | Note |
---|---|
Текущая реализация асинхронной раковины фронтенда использует запись очередей. Это вводит определенную задержку между фактом эмиссии записи и ее фактической обработкой (например, запись в файл). Такое поведение может быть неадекватным в некоторых контекстах, таких как отладка приложения, которое подвержено сбоям. |
enum severity_level { normal, warning, error }; // Complete sink type typedef sinks::asynchronous_sink< sinks::text_ostream_backend > sink_t; boost::shared_ptr< sink_t > init_logging() { boost::shared_ptr< logging::core > core = logging::core::get(); // Create a backend and initialize it with a stream boost::shared_ptr< sinks::text_ostream_backend > backend = boost::make_shared< sinks::text_ostream_backend >(); backend->add_stream( boost::shared_ptr< std::ostream >(&std::clog, boost::null_deleter())); // Wrap it into the frontend and register in the core boost::shared_ptr< sink_t > sink(new sink_t(backend)); core->add_sink(sink); // You can manage filtering and formatting through the sink interface sink->set_filter(expr::attr< severity_level >("Severity") >= warning); sink->set_formatter ( expr::stream << "Level: " << expr::attr< severity_level >("Severity") << " Message: " << expr::message ); // You can also manage backend in a thread-safe manner { sink_t::locked_backend_ptr p = sink->locked_backend(); p->add_stream(boost::make_shared< std::ofstream >("sample.log")); } // the backend gets released here return sink; }
![]() | Important |
---|---|
Если в мультимодульном приложении используется асинхронная регистрация, следует тщательно решить, когда выгружать динамически загруженные модули, которые записывают журналы. Библиотека имеет много мест, где она может в конечном итоге использовать ресурсы, которые находятся в динамически загружаемом модуле. Примерами таких ресурсов являются виртуальные таблицы, литералы строк и функции. Если какой-либо из этих ресурсов все еще используется библиотекой, когда модуль, в котором они находятся, разгружается, приложение, скорее всего, выйдет из строя. Строго говоря, эта проблема существует с любым типом раковины (и не ограничивается раковинами в первую очередь), но асинхронные раковины вводят дополнительную проблему. Нельзя сказать, какие ресурсы используются асинхронной мойкой, потому что она работает в выделенной нити и использует буферизованные записи журнала. Общего решения этого вопроса нет. Пользователям рекомендуется либо избегать разгрузки динамических модулей во время работы приложения, либо избегать асинхронной регистрации. В качестве дополнительного способа справиться с проблемой можно попытаться отключить все асинхронные раковины перед разгрузкой любых модулей, а после разгрузки воссоздать их. Однако избежать динамической разгрузки — единственный способ решить проблему полностью. |
Для того, чтобы остановить выделенные потоки подачи записей журнала на бэкэнд можно назвать<stop
>метод фронтенда. Этот метод будет называться автоматически в интерфейсном деструкторе. Метод<stop
>, в отличие от прерывания потока, завершает цикл подачи только тогда, когда подаваемая запись журнала обрабатывается бэкэндом (т.е. он не прерывает уже начатую обработку записи). Однако может случиться так, что некоторые записи все еще остаются в очереди после возвращения из метода<stop
>. Для того, чтобы смыть их в бэкэнд, требуется дополнительный вызов<feed_records
>метода. Это полезно на этапе прекращения подачи заявки.
void stop_logging(boost::shared_ptr< sink_t >& sink) { boost::shared_ptr< logging::core > core = logging::core::get(); // Remove the sink from the core, so that no records are passed to it core->remove_sink(sink); // Break the feeding loop sink->stop(); // Flush all log records that may have left buffered sink->flush(); sink.reset(); }
Нерест выделенной нити для подачи записи журнала можно подавить с помощью необязательного булевого<start_thread
>названного параметра фронтенда. В этом случае пользователь может выбрать любой способ обработки записей:
run
>метод фронтенда. Этот звонок заблокирует цикл кормления. Этот цикл можно прервать с помощью вызова<stop
>.feed_records
>. Этот метод будет обрабатывать все записи журнала, которые были в очереди фронтенда, когда звонок был выпущен, а затем вернуться.![]() | Note |
---|---|
Пользователи должны позаботиться о том, чтобы не смешивать эти два подхода одновременно. Кроме того, ни один из этих методов не следует называть, если выделенная нить подачи работает (т.е.< |
Шаблон класса<asynchronous_sink
>можно настроить с помощью стратегии очередей записей. Библиотека предлагает несколько стратегий:
unbounded_fifo_queue
>. Эта стратегия является дефолтом. Как следует из названия, очередь не ограничена по глубине и не заказывает регистрационные записи.unbounded_ordering_queue
>Как и<unbounded_fifo_queue
>, очередь имеет неограниченную глубину, но она применяет порядок на очерченных записях. Мы вернемся к заказу очередей через мгновение.bounded_fifo_queue
>. Очередь имеет ограниченную глубину, указанную в шаблонном параметре, а также стратегию обработки переполнения. Заказ записей не производится.bounded_ordering_queue
>Как<bounded_fifo_queue
>, но также применяется порядок записи журнала.![]() | Warning |
---|---|
Будьте осторожны с неограниченными стратегиями очереди. Поскольку очередь имеет неограниченную глубину, если записи журнала непрерывно генерируются быстрее, чем обрабатываются бэкэндом, очередь неконтролируемо растет, что проявляется как утечка памяти. |
Ограниченные очереди поддерживают следующие стратегии переполнения:
drop_on_overflow
>. Когда очередь заполнена, молча сбрасывайте чрезмерные регистрационные записи.block_on_overflow
>. Когда очередь заполнена, блокируйте нить регистрации до тех пор, пока поток подачи бэкэнда не обработает некоторые из стоящих в очереди записей.Например, мы могли бы изменить предыдущий пример, чтобы ограничить очередь записи до 100 элементов:
// Complete sink type typedef sinks::asynchronous_sink< sinks::text_ostream_backend, sinks::bounded_fifo_queue<100,
sinks::drop_on_overflow
> > sink_t; boost::shared_ptr< sink_t > init_logging() { boost::shared_ptr< logging::core > core = logging::core::get(); // Create a backend and initialize it with a stream boost::shared_ptr< sinks::text_ostream_backend > backend = boost::make_shared< sinks::text_ostream_backend >(); backend->add_stream( boost::shared_ptr< std::ostream >(&std::clog, boost::null_deleter())); // Wrap it into the frontend and register in the core boost::shared_ptr< sink_t > sink(new sink_t(backend)); core->add_sink(sink); // ... return sink; }
Также см.<bounded_async_log
>пример в библиотечном распределении.
Упорядочение записей может быть полезно для облегчения проблемыслабого упорядочения записей, присутствующей в многопоточных приложениях.
Стратегии упорядочивания очередей вводят небольшую задержку в обработку записей. Продолжительность задержки и предикат заказа могут быть указаны на фронтендной конструкции. Может быть полезно использоватьинструмент для упорядочивания записи журналадля реализации предикатов упорядочивания.
// Complete sink type typedef sinks::asynchronous_sink< sinks::text_ostream_backend, sinks::unbounded_ordering_queue<logging::attribute_value_ordering<
unsigned int,
std::less< unsigned int >
> > > sink_t; boost::shared_ptr< sink_t > init_logging() { boost::shared_ptr< logging::core > core = logging::core::get(); // Create a backend and initialize it with a stream boost::shared_ptr< sinks::text_ostream_backend > backend = boost::make_shared< sinks::text_ostream_backend >(); backend->add_stream( boost::shared_ptr< std::ostream >(&std::clog, boost::null_deleter())); // Wrap it into the frontend and register in the core boost::shared_ptr< sink_t > sink(new sink_t( backend,
keywords::order = logging::make_attr_ordering("LineID", std::less< unsigned int >()),
keywords::ordering_window = boost::posix_time::seconds(1)
)); core->add_sink(sink); // You can manage filtering and formatting through the sink interface sink->set_filter(expr::attr< severity_level >("Severity") >= warning); sink->set_formatter ( expr::stream << "Level: " << expr::attr< severity_level >("Severity") << " Message: " << expr::smessage ); // You can also manage backend in a thread-safe manner { sink_t::locked_backend_ptr p = sink->locked_backend(); p->add_stream(boost::make_shared< std::ofstream >("sample.log")); } // the backend gets released here return sink; }
стратегия постановки в очередь | |
log record ordering тип предиката | |
Тип значения атрибута | |
необязательный предикат сравнения значений атрибутов;< | |
Указатель на прединициализированный бэкэнд | |
лог-регистрация предиката | |
задержка обработки записей журнала |
В образце кода над фронтендом раковины будут вести регистрационные записи во внутренней очереди до одной секунды и применять порядок на основе счетчика регистрационных записей типа<unsigned
int
>. Параметр<ordering_window
>является необязательным и будет по умолчанию соответствовать некоторому достаточно малому системному значению, которое будет достаточным для поддержания хронологического потока записей журнала на бэкэнде.
Окно заказа поддерживается фронтендом даже при остановке внутренней петли подачи, так что можно было бы повторно войти в петлю, не нарушая рекорд заказа. С другой стороны, для обеспечения того, чтобы все записи журнала были смыты на бэкэнд, в конце приложения необходимо вызвать метод<flush
>.
void stop_logging(boost::shared_ptr< sink_t >& sink) { boost::shared_ptr< logging::core > core = logging::core::get(); // Remove the sink from the core, so that no records are passed to it core->remove_sink(sink); // Break the feeding loop sink->stop(); // Flush all log records that may have left buffered sink->flush(); sink.reset(); }
Этот метод также продемонстрирован в.<async_log
>пример в библиотечном распределении.
Статья Sink frontends раздела Chapter 1. Boost.Log v2 Detailed features description может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: Detailed features description ::
реклама |