![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Lambda expressionsBoost , Chapter 1. Boost.Log v2 , Detailed features description
|
![]() | Tip |
---|---|
Вы также можете использовать предикат< |
По умолчанию поведение также доступно через модификатор<or_none
>. Модифицированные заполнители могут использоваться в фильтрах и формататорах так же, как и немодифицированные.
or_default
модификаторы
value_ref
по-прежнему необходимо, если тип значения указан как последовательность типа. Кроме того,
справочный обертка может содержать тип тега, который может быть полезен для
форматирование настройки.
.
Тип<TagT
>вабстрактном описании<attr
>выше является необязательным и по умолчанию является<void
>. Это тег атрибута, который можно использовать для настройки выходных формататоров для различных атрибутов. Этот тег перенаправляется на манипулятор<to_log
>, когда извлеченное значение атрибута помещается в поток (это поведение оправдано реализацией<value_ref
>). Вот быстрый пример:
// We define our own severity levels enum severity_level { normal, notification, warning, error, critical }; // The operator is used for regular stream formatting std::ostream& operator<< (std::ostream& strm, severity_level level) { static const char* strings[] = { "normal", "notification", "warning", "error", "critical" }; if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings)) strm << strings[level]; else strm << static_cast< int >(level); return strm; } // Attribute value tag type struct severity_tag; // The operator is used when putting the severity level to log logging::formatting_ostream& operator<< ( logging::formatting_ostream& strm, logging::to_log_manip< severity_level, severity_tag > const& manip ) { static const char* strings[] = { "NORM", "NTFY", "WARN", "ERRR", "CRIT" }; severity_level level = manip.get(); if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings)) strm << strings[level]; else strm << static_cast< int >(level); return strm; } void init() { logging::add_console_log ( std::clog, // This makes the sink to write log records that look like this: // 1: <NORM> A normal severity message // 2: <ERRR> An error severity message keywords::format = ( expr::stream << expr::attr< unsigned int >("LineID") << ": <" << expr::attr< severity_level, severity_tag >("Severity") << "> " << expr::smessage ) ); }
Здесь мы указываем другого оператора форматирования для уровня тяжести, завернутого в.<to_log_manip
>Манипулятор, отмеченный тегом<severity_tag
>. Этот оператор будет называться при форматировании записей журнала, в то время как обычный<operator<<
>будет использоваться в других контекстах.
#include <boost/log/expressions/keyword_fwd.hpp
> #include <boost/log/expressions/keyword.hpp
>
Ключевые слова атрибутов могут использоваться в качестве замены.<attr
>заполнители в фильтрах и формататорах, обеспечивая при этом более краткий и менее подверженный ошибкам синтаксис. Ключевое слово атрибута может быть объявлено макросом<BOOST_LOG_ATTRIBUTE_KEYWORD
>:
BOOST_LOG_ATTRIBUTE_KEYWORD(keyword, "Keyword", type)
Здесь макрос объявляет ключевое слово<keyword
>для атрибута под названием «Ключевое слово» с типом значения<type
>. Кроме того, макрос определяет тип тега атрибута<keyword
>в пространстве имен<tag
>. Мы можем переписать предыдущий пример следующим образом:
// We define our own severity levels enum severity_level { normal, notification, warning, error, critical }; // Define the attribute keywords BOOST_LOG_ATTRIBUTE_KEYWORD(line_id, "LineID", unsigned int) BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level) // The operator is used for regular stream formatting std::ostream& operator<< (std::ostream& strm, severity_level level) { static const char* strings[] = { "normal", "notification", "warning", "error", "critical" }; if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings)) strm << strings[level]; else strm << static_cast< int >(level); return strm; } // The operator is used when putting the severity level to log logging::formatting_ostream& operator<< ( logging::formatting_ostream& strm, logging::to_log_manip< severity_level, tag::severity > const& manip ) { static const char* strings[] = { "NORM", "NTFY", "WARN", "ERRR", "CRIT" }; severity_level level = manip.get(); if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings)) strm << strings[level]; else strm << static_cast< int >(level); return strm; } void init() { logging::add_console_log ( std::clog, // This makes the sink to write log records that look like this: // 1: <NORM> A normal severity message // 2: <ERRR> An error severity message keywords::format = ( expr::stream << line_id << ": <" << severity << "> " << expr::smessage ) ); }
Ключевые слова атрибута ведут себя так же, как.<attr
>заполнители и могут использоваться как в фильтрах, так и в формататорах. Также поддерживаются<or_throw
>и<or_default
>модификаторы.
Ключевые слова также могут использоваться в выражениях поиска значений атрибутов в записях журналов и наборах значений атрибутов:
void print_severity(logging::record_view const& rec) { logging::value_ref< severity_level, tag::severity > level = rec[severity]; std::cout << level << std::endl; }
#include <boost/log/expressions/record.hpp
>
<record
>заполнитель может быть использован в<bind
>выражениях, чтобы передать весь журналвид записиобъекту связанной функции.
void my_formatter(logging::formatting_ostream& strm, logging::record_view const& rec) { // ... } namespace phoenix = boost::phoenix; sink->set_formatter(phoenix::bind(&my_formatter, expr::stream, expr::record));
![]() | Note |
---|---|
В случае фильтров заполнитель будет соответствоватьнабору значений атрибутов, а не самой записи журнала. Это связано с тем, что запись еще не построена в точке фильтрации, а фильтры работают только на наборе значений атрибутов. |
#include <boost/log/expressions/message.hpp
>
Записи журналов обычно содержат специальный атрибут «Сообщение» со значением одного из типов строк (точнее, специализации<std::basic_string
>). Этот атрибут содержит текст логового сообщения, который построен в точке создания записи. Этот атрибут создается только после фильтрации, поэтому фильтры не могут его использовать. Есть несколько ключевых слов для доступа к этому значению атрибута:
smessage
>- значение атрибута, как ожидается, будет<std::string
>wmessage
>- значение атрибута, как ожидается, будет<std::wstring
>message
>- значение атрибута, как ожидается, будет<std::string
>или<std::wstring
>Ключевое слово<message
>должно передаваться между различными типами строк, поэтому оно немного менее эффективно, чем два других ключевых слова. Если приложение может гарантировать фиксированный тип символов сообщений журнала, рекомендуется использовать соответствующее ключевое слово для повышения производительности.
// Sets up a formatter that will ignore all attributes and only print log record text sink->set_formatter(expr::stream << expr::message);
Этот раздел описывает несколько выражений, которые могут быть использованы в качестве предикатов в фильтрующих выражениях.
#include <boost/log/expressions/predicates/has_attr.hpp
>
Фильтр<has_attr
>проверяет, прикреплено ли к записи журнала значение атрибута с указанным именем и, необязательно, типом. Если тип фильтра не указан, фильтр возвращает<true
>, если найдено какое-либо значение с указанным именем. Если MPL-совместимая последовательность типов указана как тип значений, фильтр возвращает<true
>, если найдено значение с указанным именем и одним из указанных типов.
Этот фильтр обычно используется в сочетании сусловными формататорами, но он также может использоваться в качестве быстрого фильтра на основе структуры записи журнала. Например, можно использовать этот фильтр для извлечения статистических записей и маршрутизации их в конкретную раковину.
// Declare attribute keywords BOOST_LOG_ATTRIBUTE_KEYWORD(stat_stream, "StatisticStream", std::string) BOOST_LOG_ATTRIBUTE_KEYWORD(change, "Change", int) // A simple sink backend to accumulate statistic information class my_stat_accumulator : public sinks::basic_sink_backend< sinks::synchronized_feeding > { // A map of accumulated statistic values, // ordered by the statistic information stream name typedef std::map< std::string, int > stat_info_map; stat_info_map m_stat_info; public: // Destructor ~my_stat_accumulator() { // Display the accumulated data stat_info_map::const_iterator it = m_stat_info.begin(), end = m_stat_info.end(); for (; it != end; ++it) { std::cout << "Statistic stream: " << it->first << ", accumulated value: " << it->second << "\n"; } std::cout.flush(); } // The method is called for every log record being put into the sink backend void consume(logging::record_view const& rec) { // First, acquire statistic information stream name logging::value_ref< std::string, tag::stat_stream > name = rec[stat_stream]; if (name) { // Next, get the statistic value change logging::value_ref< int, tag::change > change_amount = rec[change]; if (change_amount) { // Accumulate the statistic data m_stat_info[name.get()] += change_amount.get(); } } } }; // The function registers two sinks - one for statistic information, // and another one for other records void init() { boost::shared_ptr< logging::core > core = logging::core::get(); // Create a backend and attach a stream to it boost::shared_ptr< sinks::text_ostream_backend > backend = boost::make_shared< sinks::text_ostream_backend >(); backend->add_stream( boost::shared_ptr< std::ostream >(new std::ofstream("test.log"))); // Create a frontend and setup filtering typedef sinks::synchronous_sink< sinks::text_ostream_backend > log_sink_type; boost::shared_ptr< log_sink_type > log_sink(new log_sink_type(backend)); // All records that don't have a "StatisticStream" attribute attached // will go to the "test.log" file log_sink->set_filter(!expr::has_attr(stat_stream)); core->add_sink(log_sink); // Create another sink that will receive all statistic data typedef sinks::synchronous_sink< my_stat_accumulator > stat_sink_type; boost::shared_ptr< stat_sink_type > stat_sink(new stat_sink_type()); // All records with a "StatisticStream" string attribute attached // will go to the my_stat_accumulator sink stat_sink->set_filter(expr::has_attr(stat_stream)); core->add_sink(stat_sink); } // This simple macro will simplify putting statistic data into a logger #define PUT_STAT(lg, stat_stream_name, change)\ if (true) {\ BOOST_LOG_SCOPED_LOGGER_TAG(lg, "StatisticStream", stat_stream_name);\ BOOST_LOG(lg) << logging::add_value("Change", (int)(change));\ } else ((void)0) void logging_function() { src::logger lg; // Put a regular log record, it will go to the "test.log" file BOOST_LOG(lg) << "A regular log record"; // Put some statistic data PUT_STAT(lg, "StreamOne", 10); PUT_STAT(lg, "StreamTwo", 20); PUT_STAT(lg, "StreamOne", -5); }
В этом примере записи журнала, испускаемые с макросом<PUT_STAT
>, будут направлены на бэкэнд<my_stat_accumulator
>раковины, который будет накапливать изменения, прошедшие в значениях атрибута «Изменение». Все остальные записи (даже сделанные через тот же регистратор) будут переданы в фильтровальную раковину. Это достигается с помощью взаимоисключающих фильтров, установленных для двух раковин.
Обратите внимание, что в приведенном выше примере мы расширили библиотеку двумя способами: мы определили новый фон раковины<my_stat_accumulator
>и новый макрос<PUT_STAT
>. Также обратите внимание, что<has_attr
>может принимать ключевые слова атрибутов для идентификации атрибута для проверки.
#include <boost/log/expressions/predicates/is_in_range.hpp
>
Предикат<is_in_range
>проверяет, что значение атрибута соответствует полуоткрытому диапазону (то есть возвращается<true
>, если значение атрибута<x
>удовлетворяет следующему условию:<left<=x<right
>). Например:
sink->set_filter ( // drops all records that have level below 3 or greater than 4 expr::is_in_range(expr::attr< int >("Severity"), 3, 5) );
Атрибут также может быть идентифицирован по ключевому слову атрибута или имени и типу:
sink->set_filter ( expr::is_in_range(severity, 3, 5) ); sink->set_filter ( expr::is_in_range< int >("Severity", 3, 5) );
#include <boost/log/expressions/predicates/begins_with.hpp
> #include <boost/log/expressions/predicates/ends_with.hpp
> #include <boost/log/expressions/predicates/contains.hpp
>
Предикаты<begins_with
>,<ends_with
>и<contains
>обеспечивают простой способ сопоставления значений атрибутов строки. Как следует из их названий, функции конструируют фильтры, которые возвращают<true
>, если значение атрибута начинается, заканчивается или содержит указанную подстроку соответственно. Сравнение струн чувствительно к случаю.
sink->set_filter ( // selects only records that are related to Russian web domains expr::ends_with(expr::attr< std::string >("Domain"), ".ru") );
Атрибут также может быть идентифицирован по ключевому слову атрибута или имени и типу.
#include <boost/log/expressions/predicates/matches.hpp
> // Supporting headers #include <boost/log/support/regex.hpp
> #include <boost/log/support/std_regex.hpp
> #include <boost/log/support/xpressive.hpp
> #include <boost/log/support/spirit_qi.hpp
> #include <boost/log/support/spirit_classic.hpp
>
Функция<matches
>создает фильтр, который соответствует обычному выражению или парсеру значения атрибута строки. Регулярное выражение может быть обеспеченоBoost.RegexилиBoost.Xpressive. Также поддерживаются парсеры изBoost.SpiritиBoost.Spirit2. Фильтр возвращается<true
>, если регулярное выражение совпадает или парсер успешно парсирует значение атрибута.
![]() | Note |
---|---|
Для использования этого предиката также должен быть включен соответствующий опорный заголовок. |
sink->set_filter ( expr::matches(expr::attr< std::string >("Domain"), boost::regex("www\\..*\\.ru")) );
Атрибут также может быть идентифицирован по ключевому слову атрибута или имени и типу.
#include <boost/log/expressions/predicates/channel_severity_filter.hpp
>
Этот фильтр предназначен для конкретного, но часто встречающегося случая использования. Функция<channel_severity_filter
>создает предикат, который проверяет уровень тяжести записи журнала на пороге. Предикат позволяет устанавливать разные пороги для разных каналов. Сопоставление между именами каналов и порогами строгости может быть выполнено в стиле<std::map
>с помощью оператора подстрочного кода или посредством вызова<add
>метода на самом фильтре (пример<channel_severity_filter_actor
>). Давайте посмотрим пример:
// We define our own severity levels enum severity_level { normal, notification, warning, error, critical }; // Define the attribute keywords BOOST_LOG_ATTRIBUTE_KEYWORD(line_id, "LineID", unsigned int) BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level) BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", std::string) void init() { // Create a minimal severity table filter typedef expr::channel_severity_filter_actor< std::string, severity_level > min_severity_filter; min_severity_filter min_severity = expr::channel_severity_filter(channel, severity); // Set up the minimum severity levels for different channels min_severity["general"] = notification; min_severity["network"] = warning; min_severity["gui"] = error; logging::add_console_log ( std::clog, keywords::filter = min_severity || severity >= critical, keywords::format = ( expr::stream << line_id << ": <" << severity << "> [" << channel << "] " << expr::smessage ) ); } // Define our logger type typedef src::severity_channel_logger< severity_level, std::string > logger_type; void test_logging(logger_type& lg, std::string const& channel_name) { BOOST_LOG_CHANNEL_SEV(lg, channel_name, normal) << "A normal severity level message"; BOOST_LOG_CHANNEL_SEV(lg, channel_name, notification) << "A notification severity level message"; BOOST_LOG_CHANNEL_SEV(lg, channel_name, warning) << "A warning severity level message"; BOOST_LOG_CHANNEL_SEV(lg, channel_name, error) << "An error severity level message"; BOOST_LOG_CHANNEL_SEV(lg, channel_name, critical) << "A critical severity level message"; }
Фильтр для мойки консоли состоит из фильтра<channel_severity_filter_actor
>и проверки общего уровня жесткости. Эта общая проверка будет использоваться, когда записи журнала не имеют атрибута канала или имя канала не является одним из указанных в<channel_severity_filter_actor
>инициализации. Следует отметить, что можно установить результат по умолчанию порогового фильтра, который будет использоваться в этом случае; результат по умолчанию может быть установлен методом<set_default
>. Фильтр<channel_severity_filter_actor
>настроен на ограничение уровней строгости записи для каналов «общий», «сетевой» и «гуй» — все записи в этих каналах с уровнями ниже указанных порогов не пройдут фильтр и будут проигнорированы.
Пороговый фильтр реализуется как эквивалент<std::map
>по каналам, что означает, что тип значения канала должен поддерживать частичную упорядоченность. Очевидно, что тип уровня тяжести также должен поддерживать порядок, чтобы его можно было сравнить с пороговыми значениями. По умолчанию предикат будет использовать<std::less
>эквивалент для упорядочивания имени канала и<std::greater_equal
>эквивалент для сравнения уровней тяжести. Можно настроить предикаты заказа. Проконсультируйтесь со ссылкой на класс<channel_severity_filter_actor
>и генератор<channel_severity_filter
>, чтобы увидеть соответствующие параметры шаблона.
#include <boost/log/expressions/predicates/is_debugger_present.hpp
>
Этот фильтр реализован только для Windows.<is_debugger_present
>фильтр возвращает<true
>, если приложение выполняется под отладчиком и<false
>в противном случае. Он не использует никаких значений атрибутов из записи журнала. Этот предикат обычно используется с выходом отладчикараковины.
// Complete sink type typedef sinks::synchronous_sink< sinks::debug_output_backend > sink_t; void init_logging() { boost::shared_ptr< logging::core > core = logging::core::get(); // Create the sink. The backend requires synchronization in the frontend. boost::shared_ptr< sink_t > sink(new sink_t()); // Set the special filter to the frontend // in order to skip the sink when no debugger is available sink->set_filter(expr::is_debugger_present()); core->add_sink(sink); }
Как было отмечено вучебнике, библиотека предоставляет несколько способов выражения формататоров, наиболее заметными из которых являются синтаксис потокового стиля иBoost.Format-стиль выражения. Какой из двух форматов выбран, определяется соответствующим якорным выражением. Чтобы использовать синтаксис потокового стиля, следует начать определение форматера с ключевого слова<stream
>, например:
#include <boost/log/expressions/formatters/stream.hpp
>
sink->set_formatter(expr::stream << expr1 << expr2 << ... << exprN);
Здесь выражения<expr1
>-<exprN
>могут быть либо манипуляторами, описанными в этом разделе, либо другими выражениями, приводящими к объекту, который поддерживает ввод в поток STL.
Чтобы использоватьBoost.Format-стиль синтаксиса, следует использовать<format
>конструкцию:
#include <boost/log/expressions/formatters/format.hpp
>
sink->set_formatter(expr::format("format string") % expr1 % expr2 % ... % exprN);
Строка формата, переданная ключевому слову<format
>, должна содержать позиционные заполнители для соответствующих выражений. В случае широкохарактерной регистрации строка формата должна быть широкой. Выражения<expr1
>—<exprN
>имеют то же значение, что и в варианте, похожем на поток. Следует отметить, что использование потокового синтаксиса обычно приводит к более быстрому форматированию, чем тот, который построен с ключевым словом<format
>.
Еще один полезный способ выражения форматировщиков - использование шаблонов строк. Эта часть библиотеки описана вэтомразделе и в основном предназначена для поддержки инициализации из настроек приложения.
#include <boost/log/expressions/formatters/date_time.hpp
> // Supporting headers #include <boost/log/support/date_time.hpp
>
Библиотека предоставляет формататор<format_date_time
>, предназначенный для типов значений атрибутов, связанных с датой и временем. Функция принимает имя значения атрибута и строку формата, совместимую сBoost.DateTime.
sink->set_formatter ( expr::stream << expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S") );
Значение атрибута можно отождествить с.<attr
>заполнитель илиатрибут ключевое слово.
Следующие заполнители поддерживаются в строке формата:
Table 1.2. Date format placeholders
владелец |
значение |
Пример |
---|---|---|
%a | Сокращенное название дня недели | «Мон» =>Понедельник |
«Понедельник» | ||
% b | Сокращенное название дня недели | Февраль =>Февраль |
Долгий месяц | «Февраль» | |
% | Числовой день месяца с ведущим нулем | "01" |
%e | Числовой день месяца с ведущим пространством | "1" |
%m | "01" | |
%w | Числовой день недели, 1-7 | "1" |
%y | Короткий год | «12» =>2012 |
% Y | Долгий год | «2012» |
Table 1.3. Time format placeholders
владелец |
значение |
Пример |
---|---|---|
Фракционные секунды с ведущими нулями | "000231" | |
%H, %O | ||
%I | Часы в 12-часовых часах с ведущим нулем, если меньше 10 | |
%k | "7" | |
Часы в 12-часовых часах с ведущим пространством менее 10 | "7" | |
Минуты | ||
%p | "АМ" | |
%P | Отметка AM/PM, нижний регистр | |
%q | часовой пояс ISO | «-0700» =>Горное стандартное время |
%Q | Расширенный часовой пояс ISO | "-05:00" =>Восточное стандартное время |
Секунды | "26" |
Table 1.4. Miscellaneous placeholders
владелец |
значение |
Пример |
---|---|---|
% — | Отрицательный знак в случае длительности времени, если продолжительность меньше нуля | "-" |
%+ | Признак длительности времени, даже если положительный | "+" |
% — | Сбежавший знак процента | "%" |
%T | Расширенное время ISO, эквивалентное «%H:%M:%S» |
Обратите внимание, что для того, чтобы использовать этот форматтер, вам также придется включить поддерживающий заголовок. При включении<boost/log/support/date_time.hpp
>формататор поддерживает следующие типы: Ускорение.Время:
boost::posix_time::ptime
>и<boost::local_time::local_date_time
>.boost::gregorian::date
>.boost::posix_time::time_duration
>, а также все специализированные единицы времени, такие как<boost::posix_time::seconds
>, включая субсекундные единицы.boost::gregorian::date_duration
>.![]() | Tip |
---|---|
Boost.DateTimeуже предоставляет функционал форматирования, реализованный в виде ряда локальных граней. Эта функциональность может использоваться вместо этого форматтера, хотя ожидается, что форматтер обеспечит лучшую производительность. |
#include <boost/log/expressions/formatters/named_scope.hpp
>
Формататор<format_named_scope
>предназначен для добавления поддержки гибкого форматирования значений атрибутов, названных областью. Основное использование довольно простое, и его результат аналогичен тому, что дает<attr
>:
// Puts the scope stack from outer ones towards inner ones: outer scope -> inner scope sink->set_formatter(expr::stream << expr::format_named_scope("Scopes", "%n"));
Первый аргумент называет атрибут, а второй — строку формата. Струна может содержать следующие заполнители:
Table 1.5. Named scope format placeholders
владелец |
значение |
Пример |
---|---|---|
%n | "void bar::foo()" | |
%c | "бар::фоо" | |
%C | Имя функции, без области действия функции, если область действия обозначается< | "фоо" |
"/home/user/project/foo.cpp" | ||
%F | Имя исходного файла области, без пути | |
Число строк в исходном файле | "45" |
![]() | Note |
---|---|
Как описано в описании атрибутаименованной области, можно использовать< |
В то время как строка формата описывает представление каждой названной области в списке, следующие названные аргументы позволяют настроить обход и форматирование списка:
iteration
>. Аргумент описывает направление итерации через области. Может иметь значения<forward
>(по умолчанию) или<reverse
>.delimiter
>. Аргумент может быть использован для определения разграничителей между областями. Разграничитель по умолчанию зависит от аргумента<iteration
>. Если<iteration
==forward
>по умолчанию<delimiter
>будет «->», в противном случае это будет «<-».depth
>внутренние области и, если останется больше областей, добавит эллипсис к письменной последовательности. По умолчанию формататор будет писать все имена областей.depth
>. По умолчанию строка «...» используется в качестве маркера.empty_marker
>. Аргумент может быть использован для указания строки для вывода в случае, если список области действия пуст. По умолчанию ничего не выводится в этом случае.Вот несколько примеров использования:
// Puts the scope stack in reverse order: // inner scope (file:line) <- outer scope (file:line) sink->set_formatter ( expr::stream << expr::format_named_scope( "Scopes", keywords::format = "%n (%f:%l)", keywords::iteration = expr::reverse) ); // Puts the scope stack in reverse order with a custom delimiter: // inner scope | outer scope sink->set_formatter ( expr::stream << expr::format_named_scope( "Scopes", keywords::format = "%n", keywords::iteration = expr::reverse, keywords::delimiter = " | ") ); // Puts the scope stack in forward order, no more than 2 inner scopes: // ... outer scope -> inner scope sink->set_formatter ( expr::stream << expr::format_named_scope( "Scopes", keywords::format = "%n", keywords::iteration = expr::forward, keywords::depth = 2) ); // Puts the scope stack in reverse order, no more than 2 inner scopes: // inner scope <- outer scope <<and more>>... sink->set_formatter ( expr::stream << expr::format_named_scope( "Scopes", keywords::format = "%n", keywords::iteration = expr::reverse, keywords::incomplete_marker = " <<and more>>..." keywords::depth = 2) );
![]() | Tip |
---|---|
В качестве параметра< |
#include <boost/log/expressions/formatters/if.hpp
>
Есть случаи, когда нужно проверить какое-то условие о записи журнала и форматировать его в зависимости от этого условия. Одним из примеров такой необходимости является форматирование значения атрибута в зависимости от его типа времени выполнения. Общий синтаксис условного форматировщика выглядит следующим образом:
expr::if_ (filter) [ true_formatter ] .else_ [ false_formatter ]
Те, кто знаком с выражениями лямбдаBoost.Phoenix, найдут этот синтаксис довольно знакомым. Аргумент<filter
>представляет собой фильтр, который применяется к форматируемой записи. Если он возвращается<true
>,<true_formatter
>выполняется, в противном случае<false_formatter
>выполняется. Секция<else_
>с<false_formatter
>является факультативной. Если он опущен и<filter
>дает<false
>, форматтер не выполняется. Вот пример:
sink->set_formatter ( expr::stream // First, put the current time << expr::format_date_time("TimeStamp", "%Y-%m-%d %H:%M:%S.%f") << " " << expr::if_ (expr::has_attr< int >("ID")) [ // if "ID" is present then put it to the record expr::stream << expr::attr< int >("ID") ] .else_ [ // otherwise put a missing marker expr::stream << "--" ] // and after that goes the log record text << " " << expr::message );
Бывают случаи, когда хотелось бы дополнительно пост-обработать составленную строку, прежде чем передать ее в раковину. Например, для хранения журнала в XML-файле отформатированная запись журнала должна проверяться на наличие специальных символов, имеющих особое значение в XML-документах. Именно здесь вступают декораторы.
![]() | Note |
---|---|
В отличие от большинства других формататоров, декораторы зависят от типа символа отформатированного вывода, и этот тип не может быть выведен из декорированного форматтера. По умолчанию тип символа предполагается< |
#include <boost/log/expressions/formatters/xml_decorator.hpp
>
Этот декоратор заменяет специальные символы XML (&,<, >, " и ') соответствующими токенами (<&
>,<<
>,<>
>,<"
>и<'
>соответственно). Использование выглядит следующим образом:
xml_sink->set_formatter ( // Apply the decoration to the whole formatted record expr::stream << expr::xml_decor [ expr::stream << expr::message ] );
Поскольку декораторы персонажей являются еще одним типом формататоров, их можно использовать в других контекстах, где формататоры подходят. Например, это также веский пример:
xml_sink->set_formatter ( expr::format("<message>%1%: %2%</message>") % expr::attr< unsigned int >("LineID") % expr::xml_decor[ expr::stream << expr::message ]; // Only decorate the message text );
Существует пример библиотеки, настроенной для входа в XML-файл, см.здесь.
#include <boost/log/expressions/formatters/csv_decorator.hpp
>
Этот декоратор позволяет обеспечить соответствие результирующей строки требованиям форматаCSV. В частности, он дублирует символы цитат в отформатированной строке.
csv_sink->set_formatter ( expr::stream << expr::attr< unsigned int >("LineID") << "," << expr::csv_decor[ expr::stream << expr::attr< std::string >("Tag") ] << "," << expr::csv_decor[ expr::stream << expr::message ] );
#include <boost/log/expressions/formatters/c_decorator.hpp
>
Заголовок определяет два декоратора персонажей:<c_decor
>и<c_ascii_decor
>. Первый заменяет следующие символы своими ускользающими аналогами: \ (backslash, 0x5c), \a (bell character, 0x07), \b (backspace, 0x08), \f (formfeed, 0x0c), \n (newline, 0x0a), \r (carriage return, 0x0d), \t (horizontal tabulation, 0x09), \v (vertical tabulation, 0x0b), ' (apostroph, 0x27), ' (quote, 0x22), ? (question mark, 0x3f).<c_ascii_decor
>декоратор делает то же самое, но также заменяет все другие непечатные и не-ASCII символы с ускользающими шестнадцатеричными кодами символов в обозначении C (например, "\x8c"). Использование похоже на другие декораторы персонажей:
sink->set_formatter ( expr::stream << expr::attr< unsigned int >("LineID") << ": [" << expr::c_decor[ expr::stream << expr::attr< std::string >("Tag") ] << "] " << expr::c_ascii_decor[ expr::stream << expr::message ] );
#include <boost/log/expressions/formatters/char_decorator.hpp
>
Этот декоратор позволяет пользователю определить собственное отображение замены персонажа в одной из двух форм. Первая форма представляет собой диапазон струн<std::pair
>(который может быть струнами в стиле C или диапазонами символов, включая<std::string
>s). Струны в<first
>элементах пар будут заменены на<second
>элементы соответствующей пары.
std::array< std::pair< const char*, const char* >, 3 > shell_escapes = { { "\"", "\\\"" }, { "'", "\\'" }, { "$", "\\$" } }; sink->set_formatter ( expr::stream << expr::char_decor(shell_escapes) [ expr::stream << expr::message ] );
Вторая форма представляет собой две одноразмерные последовательности строк; первая содержит шаблоны поиска, а вторая — соответствующие замены.
std::array< const char*, 3 > shell_patterns = { "\"", "'", "$" }; std::array< const char*, 3 > shell_replacements = { "\\\"", "\\'", "\\$" }; sink->set_formatter ( expr::stream << expr::char_decor(shell_patterns, shell_replacements) [ expr::stream << expr::message ] );
В обоих случаях шаблоны не интерпретируются и ищутся в отформатированных символах в оригинальной форме.
#include <boost/log/expressions/formatters/max_size_decorator.hpp
>
Иногда может быть полезно иметь возможность ограничить размер выхода форматтера или его части. Например, предел может быть установлен раковиной или требуемым выходным форматом. Декоратор<max_size_decor
>позволяет применять такой предел. Рассмотрим простой пример:
sink->set_formatter ( expr::stream << expr::max_size_decor< char >(20) [ expr::stream << expr::message ] );
![]() | Note |
---|---|
Явный параметр шаблона для< |
В этом примере декоратор ограничивает сообщение журнала не более чем 20кодовыми единицамитипа<char
>и удаляет остальное с выхода. Если бы у нас была такая запись:
BOOST_LOG(lg) << "The quick brown fox jumps over the lazy dog";
Результат будет выглядеть так:
The quick brown fox
Однако, глядя на этот вывод в файле журнала, неясно, содержал ли исходный вывод что-либо еще. Кто-то может захотеть указать факт усечения сообщения, если оно произойдет. Для этой цели декоратор позволяет указать маркер переполнения, который будет размещен в конце усеченного выхода, если усечение имело место. Мы можем изменить приведенный выше пример следующим образом:
sink->set_formatter ( expr::stream << expr::max_size_decor(20, ">>>") [ expr::stream << expr::message ] );
![]() | Tip |
---|---|
Тип символа форматера выводится из типа символа маркера переполнения, поэтому его можно опустить. |
Теперь наш журнал будет выглядеть так на выходе:
The quick brown f>>>
Этот вывод делает более очевидным, что в исходном сообщении было больше. Отметим также, что длина вывода составляет еще 20 символов; маркер заменил последние символы усеченного вывода.
![]() | Tip |
---|---|
Для правильной работы усечения символов и позиционирования маркеров в многобайтных кодировках важно правильно настроить используемую форматировщиком локализацию. В частности, грань< |
Как и любой другой формататор,<max_size_decor
>может участвовать в более сложных выражениях форматирования и ограничивать длину только части сообщения.
sink->set_formatter ( expr::stream << expr::format_date_time("TimeStamp", "%Y-%m-%d %H:%M:%S.%f") << " [" << expr::max_size_decor(20, ">>>") [ expr::stream << expr::message ] << "]" );
Вышеупомянутый формататор может производить такой вывод:
2016-08-10 00:36:44.028473 [The quick brown f>>>]
Статья Lambda expressions раздела Chapter 1. Boost.Log v2 Detailed features description может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: Detailed features description ::
реклама |