Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Lambda expressions

Boost , Chapter 1. Boost.Log v2 , Detailed features description

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Как было указано вучебнике, фильтры и формататоры могут быть указаны как выражения Ламбда с заполнителями для значений атрибутов. В этом разделе будут описаны заполнители, которые можно использовать для создания более сложных выражений лямбда.

Также есть способ указать фильтр в виде шаблона строки. Это может быть полезно для инициализации из настроек приложения. Эта часть библиотеки описаназдесь.

#include <boost/log/expressions/attr_fwd.hpp>
#include <boost/log/expressions/attr.hpp>

Заполнитель<attr>представляет значение атрибута в выражениях шаблона. Учитывая вид записи или набор значений атрибутов, заполнитель попытается извлечь указанное значение атрибута из аргумента при вызове. Это можно приблизительно описать следующим псевдокодом:

logging::value_ref< T, TagT > val = expr::attr< T, TagT >(name)(rec);

где<val>- ссылкана извлеченное значение,<name>и<T>- значение атрибутаимяи тип,<TagT>- факультативный тег (мы вернёмся к нему через мгновение) и<rec>- logзапись видилинабор значений атрибута.<T>может быть последовательностьютипа Boost.MPLс возможными ожидаемыми типами значения; извлечение будет успешным, если тип значения соответствует одному из типов в последовательности.

Заполнитель<attr>может использоваться в выраженияхBoost.Phoenix, включая выражение<bind>.

bool my_filter(logging::value_ref< severity_level, tag::severity > const& level,
               logging::value_ref< std::string, tag::tag_attr > const& tag)
{
    return level >= warning || tag == "IMPORTANT_MESSAGE";
}
void init()
{
    // ...
    namespace phoenix = boost::phoenix;
    sink->set_filter(phoenix::bind(&my_filter, severity.or_none(), tag_attr.or_none()));
    // ...
}

Заполнитель можно использовать как в фильтрах, так и в формататорах:

sink->set_filter
(
    expr::attr< int >("Severity") >= 5 &&
    expr::attr< std::string >("Channel") == "net"
);
sink->set_formatter
(
    expr::stream
        << expr::attr< int >("Severity")
        << " [" << expr::attr< std::string >("Channel") << "] "
        << expr::smessage
);

Звонок в<set_filter>регистрирует составной фильтр, который состоит из двух элементарных подфильтров: первый проверяет уровень тяжести, а второй проверяет название канала. Звонок<set_formatter>устанавливает формататор, который составляет строку, содержащую уровень серьезности и название канала вместе с текстом сообщения.

По умолчанию, когда запрашиваемое значение атрибута не найдено в записи,<attr>вернет пустую ссылку. В случае фильтров это приведет к<false>в любом упорядочении выражений, а в случае формататоров выход из заполнителя будет пустым. Такое поведение можно изменить:

  • Исключение<missing_value>или<invalid_type>в зависимости от причины отказа. Добавить<or_throw>модификатор:
sink->set_filter
(
    expr::attr< int >("Severity").or_throw() >= 5 &&
    expr::attr< std::string >("Channel").or_throw() == "net"
);
  • Вместо этого использовать значение по умолчанию. Добавить<or_default>модификатор с желаемым значением по умолчанию:
sink->set_filter
(
    expr::attr< int >("Severity").or_default(0) >= 5 &&
    expr::attr< std::string >("Channel").or_default(std::string("general")) == "net"
);
[Tip]Tip

Вы также можете использовать предикат<has_attr>для реализации фильтров и формататоров, обусловленных наличием значения атрибута.

По умолчанию поведение также доступно через модификатор<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]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]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]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

Имя функции, без области действия функции, если область действия обозначается<BOOST_LOG_FUNCTION>, в противном случае полное название области действия. См. примечание ниже.

"фоо"

"/home/user/project/foo.cpp"

%F

Имя исходного файла области, без пути

Число строк в исходном файле

"45"


[Note]Note

Как описано в описании атрибутаименованной области, можно использовать<BOOST_LOG_FUNCTION>макрос для автоматического генерирования имен области из названия прилагаемой функции. К сожалению, фактический формат генерируемых строк зависит от компилятора и во многих случаях включает в себя полную подпись функции. Когда указывается флаг формата «%c» или «%C», библиотека пытается разобрать генерируемую строку для извлечения имени функции. Поскольку синтаксис C++ очень зависит от контекста и сложен, во всех случаях невозможно правильно разобрать подпись функции, поэтому библиотека в основном гадает. В зависимости от формата строки это может привести к сбою или привести к неправильным результатам. В частности, операторы преобразования типов могут создавать проблемы для парсера. В случае, если парсер не распознает подпись функции, библиотека возвращается к использованию всей строки (то есть ведет себя эквивалентно флагу «%n»). Чтобы облегчить проблему, пользователь может заменить проблемное использование<BOOST_LOG_FUNCTION>макросом<BOOST_LOG_NAMED_SCOPE>и явно написать желаемое название области. Область имен, обозначенных<BOOST_LOG_NAMED_SCOPE>, не будет интерпретироваться библиотекой и будет выводиться как есть. В целом, по причинам переносимости и производительности во время выполнения предпочтительно всегда использовать флаг формата<BOOST_LOG_NAMED_SCOPE>и «%n».

В то время как строка формата описывает представление каждой названной области в списке, следующие названные аргументы позволяют настроить обход и форматирование списка:

Вот несколько примеров использования:

// 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]Tip

В качестве параметра<incomplete_marker>может быть указана пустая строка, и в этом случае не будет никаких указаний на усечение списка.

#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]Note

В отличие от большинства других формататоров, декораторы зависят от типа символа отформатированного вывода, и этот тип не может быть выведен из декорированного форматтера. По умолчанию тип символа предполагается<char>. Если формататор используется для составления строки с широкими символами, подготовьте имя декоратора буквой<w>(например, используйте<wxml_decor>вместо<xml_decor>). Кроме того, для каждого декоратора есть функция генератора, которая принимает тип символа в качестве параметра шаблона; функция называется аналогично декоратору, подготовленному с префиксом<make_>(например,<make_xml_decor>).

#include <boost/log/expressions/formatters/xml_decorator.hpp>

Этот декоратор заменяет специальные символы XML (&,<, >, " и ') соответствующими токенами (<&amp;>,<&lt;>,<&gt;>,<&quot;>и<&apos;>соответственно). Использование выглядит следующим образом:

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]Note

Явный параметр шаблона для<max_size_decor>определяет тип символа, который используется форматировщиком. В этом примере строка, создаваемая форматером, содержит символы типа<char>, отсюда и параметр шаблона.

В этом примере декоратор ограничивает сообщение журнала не более чем 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]Tip

Тип символа форматера выводится из типа символа маркера переполнения, поэтому его можно опустить.

Теперь наш журнал будет выглядеть так на выходе:

The quick brown f>>>

Этот вывод делает более очевидным, что в исходном сообщении было больше. Отметим также, что длина вывода составляет еще 20 символов; маркер заменил последние символы усеченного вывода.

[Tip]Tip

Для правильной работы усечения символов и позиционирования маркеров в многобайтных кодировках важно правильно настроить используемую форматировщиком локализацию. В частности, грань<std::codecvt>в области должна правильно распознавать многобайтовые последовательности, соответствующие одному символу на выходе. Можно использоватьBoost.Localeдля генерации местоположения, а затем установить его в интерфейс раковины, позвонив<imbue>(см.<basic_formatting_sink_frontend>для справки). Если тип выходного символа<wchar_t>,<char16_t>или<char32_t>, библиотека предполагает, что выход кодируется в UTF-16 или UTF-32, в зависимости от размера типа символа. Поскольку усечение может происходить в середине многоэлементного символа, усеченный выход, производимый декоратором, иногда может быть немного короче указанного предела.

Как и любой другой формататор,<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>>>]

PrevUpHomeNext

Статья Lambda expressions раздела Chapter 1. Boost.Log v2 Detailed features description может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Detailed features description ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 18:00:56/0.020183086395264/0