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

Attributes

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/attributes/attribute.hpp>
#include <boost/log/attributes/attribute_cast.hpp>
#include <boost/log/attributes/attribute_value.hpp>

Все атрибуты в библиотеке реализуются с использованиемpimpl idiom, или более конкретно - shared pimpl idiom. Каждый атрибут предоставляет класс интерфейса, который происходит от атрибута.класс и класс реализации, который происходит отimpl. Класс интерфейса содержит только указатель отсчета ссылки на фактическую реализацию атрибута; этот указатель является членом атрибута.класс, поэтому производные классы интерфейса не имеют никаких элементов данных. Когда класс интерфейса построен по умолчанию, он создает соответствующий объект реализации и инициализирует атрибут.базовый класс с указанием на реализацию. Поэтому сутенерская природа атрибутов прозрачна для пользователей в типичном рабочем процессе.

Общий дизайн сутенера имеет большое значение в нескольких случаях. Одним из таких случаев является копирование атрибута. Операция копирования неглубокая, поэтому несколько объектов интерфейса могут относиться к одному объекту реализации. Невозможно глубоко скопировать атрибут. Другой случай — по умолчанию построениеатрибута, который создает пустой объект, не относящийся к реализации. Атрибуты в таком пустом состоянии не должны передаваться библиотеке, но могут быть полезны в некоторых случаях, например, когда требуется запоздалая инициализация переменной.

Интерфейс атрибутов можно отатрибутадо фактического класса интерфейсов. Для этого нужно применитьатрибут_cast:

logging::attribute attr = ...;
attrs::constant< int > const_attr = logging::attribute_cast< attrs::constant< int > >(attr);

В этом примере литье будет успешным (т.е.const_attrбудет непустым), если атрибутattrпервоначально был создан какattrs::константа<int>. Поскольку все данные хранятся в объекте реализации, никакие данные не теряются в процессе литья.

Основной целью атрибутов является генерация значений атрибутов. Значения семантически отличаются от атрибутов. Такое разделение позволяет реализовать атрибуты, которые могут возвращать разные значения в разные моменты времени (например, связанные с часами атрибуты), и, с другой стороны, позволяет использовать разные значения одного и того же атрибута независимо. Интерфейсатрибутаимеет метод под названиемget_value, который возвращает фактическое значение атрибута. Значения атрибутов также реализуются с использованием общего подхода pimpl, класс интерфейсаатрибут_значениеи классы реализации происходят отimpl.

Объект значения атрибута в основном предназначен для хранения фактического значения атрибута и реализации отправки типа, чтобы иметь возможность извлекать сохраненное значение. Не следует путать тип объекта значения атрибута и тип хранимого значения. Первый в большинстве случаев не нужен пользователям и обеспечивает стирание типа, но последний необходим для извлечения значения. Для краткости мы называем тип хранимого значения атрибута просто типом значения атрибута в этой документации.

#include <boost/log/attributes/constant.hpp>

Наиболее простым и часто используемым типом атрибутов является постоянное значение какого-либо типа. Этот тип атрибута реализован с шаблоном классаконстанта. Шаблон параметризируется с типом значения атрибута. Постоянное значение должно быть передано конструктору атрибутов. Вот пример:

void foo()
{
    src::logger lg;
    // Register a constant attribute that always yields value -5
    lg.add_attribute("MyInteger", attrs::constant< int >(-5));
    // Register another constant attribute. Make it a string this time.
    lg.add_attribute("MyString", attrs::constant< std::string >("Hello world!"));
    // There is also a convenience generator function. "MyInteger2" is constant< int > here.
    lg.add_attribute("MyInteger2", attrs::make_constant(10));
}

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

#include <boost/log/attributes/mutable_constant.hpp>

Этот тип атрибута является расширением дляпостоянного атрибута. В дополнение к возможности хранить некоторое значение, шаблон классаmutable_constantимеет два различия:

  • позволяет изменять сохраненное значение без перерегистрации атрибута;
  • позволяет синхронизировать магазины и считывает сохраненное значение

Чтобы изменить сохраненное значение атрибута, необходимо назвать методset:

void foo()
{
    src::logger lg;
    // Register a mutable constant attribute that always yields value -5
    attrs::mutable_constant< int > attr(-5);
    lg.add_attribute("MyInteger", attr);
    BOOST_LOG(lg) << "This record has MyInteger == -5";
    // Change the attribute value
    attr.set(100);
    BOOST_LOG(lg) << "This record has MyInteger == 100";
}

В многопоточных приложениях вызовы метода, установленные, должны быть сериализованы с вызовамиget_value(которые, вообще говоря, происходят в каждой сделанной записи журнала). По умолчаниюmutable_constantникак не сериализует вызовы, предполагая, что пользователь сделает это внешне. Тем не менее, шаблонmutable_constantпредоставляет три дополнительных аргумента шаблона: примитивный тип синхронизации, эксклюзивный тип блокировки и общий тип блокировки. Если указан примитивный тип синхронизации, то используемый эксклюзивный тип блокировки является обязательным параметром. Если тип совместно используемого замка не указан, атрибут вернется к эксклюзивному замку вместо общих замков. Например:

// This mutable constant will always lock exclusively
// either for reading or storing the value
typedef attrs::mutable_constant<
    int,                                        // attribute value type
    boost::mutex,                               // synchronization primitive
    boost::lock_guard< boost::mutex >           // exclusive lock type
> exclusive_mc;
exclusive_mc my_int1(10);
// This mutable constant will use shared clocking for reading the value
// and exclusive locking for storing
typedef attrs::mutable_constant<
    int,                                        // attribute value type
    boost::shared_mutex,                        // synchronization primitive
    boost::unique_lock< boost::shared_mutex >,  // exclusive lock type
    boost::shared_lock< boost::shared_mutex >   // shared lock type
> shared_mc;
shared_mc my_int2(20);
BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT(my_logger, src::logger_mt)
{
    src::logger_mt lg;
    lg.add_attribute("MyInteger1", my_int1);
    lg.add_attribute("MyInteger2", my_int2);
    return lg;
}
void foo()
{
    src::logger_mt& lg = get_my_logger();
    // This is safe, even if executed in multiple threads
    my_int1.set(200);
    BOOST_LOG(lg) << "This record has MyInteger1 == 200";
    my_int2.set(300);
    BOOST_LOG(lg) << "This record has MyInteger2 == 300";
}

Изменяемые константы часто используются в качестве вспомогательных атрибутов внутри регистраторов для хранения атрибутов, которые могут изменяться на некоторых событиях. В отличие от обычных констант, которые требуют перерегистрации в случае изменения стоимости, изменчивые константы позволяют изменять значение на месте.

#include <boost/log/attributes/counter.hpp>

Счетчики являются одним из самых простых атрибутов, которые генерируют новое значение при каждом запросе. Счетчики часто используются для идентификации записей журнала или для подсчета некоторых событий, например, принятых сетевых соединений. Шаблон классасчетчикобеспечивает такую функциональность. Данный шаблон параметризируется типом счетчика, который должен поддерживать арифметические операции, такие какоператор+иоператор-. Атрибут счетчика позволяет уточнить начальное значение и шаг (который может быть отрицательным) на конструкцию.

BOOST_LOG_INLINE_GLOBAL_LOGGER_INIT(my_logger, src::logger_mt)
{
    src::logger_mt lg;
    // This counter will count lines, starting from 0
    lg.add_attribute("LineCounter", attrs::counter< unsigned int >());
    // This counter will count backwards, starting from 100 with step -5
    lg.add_attribute("CountDown", attrs::counter< int >(100, -5));
    return lg;
}
void foo()
{
    src::logger_mt& lg = get_my_logger();
    BOOST_LOG(lg) << "This record has LineCounter == 0, CountDown == 100";
    BOOST_LOG(lg) << "This record has LineCounter == 1, CountDown == 95";
    BOOST_LOG(lg) << "This record has LineCounter == 2, CountDown == 90";
}
[Note]Note

Не ожидайте, что записи журнала с атрибутомвсегда будут иметь значения восходящего или нисходящего счетчика в полученном журнале. В многопоточных приложениях встречные значения, полученные различными потоками, могут поступать в раковину в любом порядке.Обоснованиедля более подробного объяснения того, почему это может произойти. По этой причине правильнее сказать, что атрибутгенерирует идентификатор в порядке восходящего или нисходящего, а не считает записи журнала в любом порядке.

#include <boost/log/attributes/clock.hpp>

Одной из «обязательных» особенностей любой библиотеки журналов является поддержка прикрепления метки времени к каждой записи журнала. Библиотека предоставляет для этой цели два атрибута:utc_clockиlocal_clock. Первый возвращает текущее время UTC, а второй возвращает текущее местное время. В любом случае возвращаемая временная метка приобретается с максимальной точностью для целевой платформы. Значение атрибутаповышает::posix_time::ptime(см.Boost.DateTime). Использование довольно простое:

BOOST_LOG_DECLARE_GLOBAL_LOGGER(my_logger, src::logger_mt)
void foo()
{
    logging::core::get()->add_global_attribute(
        "TimeStamp",
        attrs::local_clock());
    // Now every log record ever made will have a time stamp attached
    src::logger_mt& lg = get_my_logger();
    BOOST_LOG(lg) << "This record has a time stamp";
}
#include <boost/log/attributes/timer.hpp>

Атрибуттаймераочень полезен, когда есть необходимость оценить продолжительность какого-то длительного процесса. Атрибут возвращает время, прошедшее с момента построения атрибута. Тип значения атрибута —boost::posix_time::ptime::time_duration_type(см.Boost.DateTime).

// The class represents a single peer-to-peer connection
class network_connection
{
    src::logger m_logger;
public:
    network_connection()
    {
        m_logger.add_attribute("Duration", attrs::timer());
        BOOST_LOG(m_logger) << "Connection established";
    }
    ~network_connection()
    {
        // This log record will show the whole life time duration of the connection
        BOOST_LOG(m_logger) << "Connection closed";
    }
};

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

[Tip]Tip

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

#include <boost/log/attributes/named_scope.hpp>
// Supporting headers
#include <boost/log/support/exception.hpp>

Библиотека журналов поддерживает отслеживание стека областей во время выполнения приложения. Этот стек может быть записан для входа в систему или использоваться для других нужд (например, для сохранения точной последовательности вызовов, которая привела к исключению при броске). Каждый элемент стека содержит следующую информацию (см. определение шаблона структурыnamed_scope_entry):

  • Сфера применения. Она может быть определена пользователем или сгенерирована компилятором, но в любом случае онадолжна быть постоянной строкой(см.Обоснование).
  • Имя исходного файла, где начинается область действия. Обычно это результат стандартного__FILE__макрорасширения. Как и название области, имя файладолжно быть постоянным строковым буквальным.
  • Номер строки в исходном файле. Обычно это результат стандартного__LINE__макрорасширения.

Стек области применения реализуется в качестве глобального хранилища, специфичного для потоков. Существует атрибутnamed_scope, который позволяет подключать этот стек в лесозаготовительный трубопровод. Этот атрибут генерирует значение вложенного типаnamed_scope::scope_stack, которое является экземпляром стека scope. Атрибут может быть зарегистрирован следующим образом:

logging::core::get()->add_global_attribute("Scope", attrs::named_scope());

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

Теперь мы можем отметить области выполнения макросамиBOOST_LOG_FUNCTIONиBOOST_LOG_NAMED_SCOPE(последний принимает название области в качестве аргумента). Эти макросы автоматически добавляют информацию о местоположении источника к каждой позиции области. Ниже приводится пример:

void foo(int n)
{
    // Mark the scope of the function foo
    BOOST_LOG_FUNCTION();
    switch (n)
    {
    case 0:
        {
            // Mark the current scope
            BOOST_LOG_NAMED_SCOPE("case 0");
            BOOST_LOG(lg) << "Some log record";
            bar(); // call some function
        }
        break;
    case 1:
        {
            // Mark the current scope
            BOOST_LOG_NAMED_SCOPE("case 1");
            BOOST_LOG(lg) << "Some log record";
            bar(); // call some function
        }
        break;
    default:
        {
            // Mark the current scope
            BOOST_LOG_NAMED_SCOPE("default");
            BOOST_LOG(lg) << "Some log record";
            bar(); // call some function
        }
        break;
    }
}

После выполненияfooмы сможем увидеть в журнале, что функцияbarбыла вызвана изfooи, точнее, из утверждения случая, которое соответствует значениюn. Это может быть очень полезно при отслеживании тонких ошибок, которые появляются только тогда, когдабарвызывается из определенного места (например, еслибар)в данном конкретном месте принимаются недействительные аргументы.

[Note]Note

BOOST_LOG_FUNCTIONМакро использует расширения, специфичные для компилятора, для генерации имени области действия из прилагаемой функции. C++11 определяет стандартный макрос__func__для этой цели, но он не поддерживается повсеместно. Кроме того, формат строки не стандартизирован и может варьироваться от одного компилятора к другому. По этой причине рекомендуется использоватьBOOST_LOG_NAMED_SCOPE.вместоBOOST_LOG_FUNCTIONдля обеспечения последовательного и портативного поведения.

Другим хорошим вариантом использования является прикрепление информации стека области применения к исключению. С помощьюBoost.Exceptionможно:

void bar(int x)
{
    BOOST_LOG_FUNCTION();
    if (x < 0)
    {
        // Attach a copy of the current scope stack to the exception
        throw boost::enable_error_info(std::range_error("x must not be negative"))
            << logging::current_scope();
    }
}
void foo()
{
    BOOST_LOG_FUNCTION();
    try
    {
        bar(-1);
    }
    catch (std::range_error& e)
    {
        // Acquire the scope stack from the exception object
        BOOST_LOG(lg) << "bar call failed: " << e.what() << ", scopes stack:\n"
            << *boost::get_error_info< logging::current_scope_info >(e);
    }
}
[Note]Note

Для компиляции этого кода необходимо включить заголовок поддержкиBoost.Exception.

[Note]Note

Мы не вводим в исключение атрибутnamed_scope. Поскольку стеки области действия поддерживаются во всем мире, выбрасывание исключения приведет к раскручиванию стека и, как следствие, усечению глобального стека. Вместо этого мы создаем копию стека прицела, позвонивcurrent_scopeна месте броска. Эта копия будет сохранена нетронутой, даже если глобальный экземпляр стека изменится во время раскручивания стека.

#include <boost/log/attributes/current_process_id.hpp>

Часто полезно знать идентификатор процесса, который создает журнал, особенно если журнал может в конечном итоге объединить выход различных процессов. Атрибутcurrent_process_idпредставляет собой константу, которая форматируется в идентификатор текущего процесса. Тип значения атрибута может быть определен посредствомcurrent_process_id::value_typetypedef.

void foo()
{
    logging::core::get()->add_global_attribute(
        "ProcessID",
        attrs::current_process_id());
}
#include <boost/log/attributes/current_process_name.hpp>

current_process_nameпроизводитstd::значения строкис исполняемым названием текущего процесса.

[Note]Note

Этот атрибут не является универсально портативным, хотя Windows, Linux и OS X поддерживаются. Атрибут может работать и на других системах POSIX, но он не был протестирован. Если имя процесса не может быть получено, атрибут сгенерирует строку с идентификатором процесса.

void foo()
{
    logging::core::get()->add_global_attribute(
        "Process",
        attrs::current_process_name());
}
#include <boost/log/attributes/current_thread_id.hpp>

Многопоточные сборки библиотеки также поддерживают атрибутcurrent_thread_idс типом значенияcurrent_thread_id::value_type. Атрибут будет генерировать значения, специфичные для вызывающей нити. Использование аналогично процессу id.

void foo()
{
    logging::core::get()->add_global_attribute(
        "ThreadID",
        attrs::current_thread_id());
}
[Tip]Tip

Возможно, вы заметили, что атрибут зарегистрирован по всему миру. Это не приведет к тому, что все потоки, имеющие тот же ThreadID в записях журналов, что и атрибут, всегда будут возвращать значение, специфичное для потока. Дополнительным преимуществом является то, что вам не нужно делать что-то в процедурах инициализации потока, чтобы иметь значение атрибута потока в записях журнала.

#include <boost/log/attributes/function.hpp>

Этот атрибут представляет собой простую обертку вокруг определяемого пользователем функционального объекта. Каждая попытка получить значение атрибута приводит к вызову объекта функции. Результат вызова возвращается в качестве значения атрибута (это означает, что функция не должна возвращатьпустоту). Атрибут объекта функции может быть построен с помощью функции помощникаmake_function, такой как:

void foo()
{
    logging::core::get()->add_global_attribute("MyRandomAttr", attrs::make_function(&std::rand));
}

Также поддерживаются автоматически генерируемые функциональные объекты, подобные тем, которые определены вBoost.Bindили STL.

[Note]Note

Некоторые недостающие компиляторы могут не поддерживатьрезультат_. Эта метафункция используется в функцииmake_functionдля автоматического обнаружения возвращаемого типа функционального объекта. Еслирезультат_нарушает или обнаруживает неправильный тип, можно попытаться явно указать тип возврата объекта функции в качестве аргумента шаблона дляфункции make_function.

#include <boost/log/attributes/attribute_name.hpp>

Имена атрибутов представлены объектамиатрибут_имя, которые используются в качестве ключей в ассоциативных контейнерах атрибутов, используемых библиотекой.атрибут_имяобъект может быть создан из строки, поэтому большую часть времени его использование прозрачно.

Имя не хранится как строка внутри.атрибут_имяобъект. Вместо этого генерируется универсальный идентификатор процесса, связанный с конкретным именем. Эта связь сохраняется до окончания процесса, поэтому каждый разатрибут_имяобъект создан для того же имени, он получает тот же идентификатор. Тем не менее, ассоциация не стабильна в разных версиях приложения.

[Warning]Warning

Поскольку связь между именами строк и идентификаторами включает в себя некоторое государственное распределение, не рекомендуется использовать внешние или известные изменения строк для имен атрибутов. Даже если имя не используется в каких-либо записях журнала, ассоциация сохраняется в любом случае. Непрерывное построениеатрибута_имяобъектов с уникальными именами строк может проявляться как утечка памяти.

Работа с идентификаторами намного эффективнее, чем со строками. Например, копирование не требует динамического распределения памяти, а операторы сравнения очень легкие. С другой стороны, при необходимости легко получить считываемое человеком имя атрибута для презентации.

Классатрибут_nameподдерживает пустое (неинициализированное) состояние при построении по умолчанию. В этом состоянии имя объекта не равно любому другому инициализируемому имени объекта. Имена атрибутов не должны передаваться в библиотеку, но могут быть полезны в некоторых контекстах (например, когда требуется отсроченная инициализация).

#include <boost/log/attributes/attribute_set.hpp>

Набор атрибутов представляет собой неупорядоченный ассоциативный контейнер, который отображаетимена атрибутовнаатрибуты. Он используется врегистраторахирегистрационном ядредля хранения исходных, нитевидных и глобальных атрибутов. Интерфейс очень похож на ассоциативные контейнеры STL и описан в ссылке классаатрибут_set.

#include <boost/log/attributes/attribute_value_set.hpp>

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

Кроме того, набор может быть построен из трехнаборов атрибутов, которые интерпретируются как наборы исходных, нитевидных и глобальных атрибутов. Конструктор принимает значения атрибутов из трех наборов атрибутов в единый набор значений атрибутов. После строительстваатрибут_значение_множествосчитается находящимся в незамороженном состоянии. Это означает, что контейнер может содержать ссылки на элементы наборов атрибутов, используемых в качестве источника для построения набора значений. В этом состоянии ни наборы атрибутов, ни набор значений не должны каким-либо образом изменяться, поскольку это может привести к повреждению набора значений. Набор значений может использоваться для чтения в этом состоянии, его операции поиска будут выполняться как обычно. Набор значений может быть заморожен путем вызова методазамораживания; набор больше не будет присоединен к исходным наборам атрибутов и будет доступен для дальнейших вставок после этого вызова. Библиотека гарантирует, что набор значений всегда замораживается, когда запись журнала возвращается из регистрационного ядра; наборнезамораживается во время фильтрации.

[Tip]Tip

В незамороженном состоянии набор значений может не иметь всех значений атрибутов, полученных из атрибутов. Он будет получать только те значения, которые запрашиваются фильтрами. После замораживания контейнер имеет все значения атрибутов. Этот переход позволяет оптимизировать библиотеку так, чтобы значения атрибутов приобретались только при необходимости.

Для получения дополнительной информации о интерфейсе контейнера, пожалуйста, обратитесь к ссылкеатрибут_value_set.

Поскольку значения атрибутов не отображают сохраненное значение в интерфейсе, для получения сохраненного значения необходим API. Библиотека предоставляет два API для этой цели: посещение и извлечение ценности.

#include <boost/log/attributes/value_visitation_fwd.hpp>
#include <boost/log/attributes/value_visitation.hpp>

Посещение ценности атрибута реализует шаблон дизайна посетителя, отсюда и название. Пользователь должен предоставить унарный функциональный объект (посетитель), на который будет ссылаться сохраненное значение атрибута. Абонент также должен предоставить ожидаемый тип или набор возможных типов сохраненного значения. Очевидно, что посетитель должен быть в состоянии получить аргумент ожидаемого типа. Посещение будет успешным только в том случае, если сохраненный тип соответствует ожиданиям.

Для того чтобы применить посетителя, следует вызвать функциюна значение атрибута. Давайте посмотрим пример:

// Our attribute value visitor
struct print_visitor
{
    typedef void result_type;
    result_type operator() (int val) const
    {
        std::cout << "Visited value is int: " << val << std::endl;
    }
    result_type operator() (std::string const& val) const
    {
        std::cout << "Visited value is string: " << val << std::endl;
    }
};
void print_value(logging::attribute_value const& attr)
{
    // Define the set of expected types of the stored value
    typedef boost::mpl::vector< int, std::string > types;
    // Apply our visitor
    logging::visitation_result result = logging::visit< types >(attr, print_visitor());
    // Check the result
    if (result)
        std::cout << "Visitation succeeded" << std::endl;
    else
        std::cout << "Visitation failed" << std::endl;
}

См. полный код.

В этом примере мы печатаем сохраненное значение атрибута в нашемprint_visitor. Мы ожидаем, что значение атрибута будет иметь либоint, либоstd::строкасохраненного типа; только в этом случае посетитель будет вызван и результат посещения будет положительным. В случае отказа классvisitation_resultпредоставляет дополнительную информацию о причине отказа. Класс имеет метод под названиемкод, который возвращает код ошибки посещения. Возможны следующие коды ошибок:

  • ok- посещение успешно, посетитель был вызван; результат посещения является положительным, когда этот код используется
  • value_not_found- посещение не удалось, потому что запрошенное значение не было найдено; этот код используется, когда посещение применяется к записи журнала или набору значений атрибутов, а не к одному значению
  • value_has_invalid_type- посещение не удалось, поскольку значение имеет тип, отличающийся от любого из ожидаемых типов

По умолчанию результат функции посетителя игнорируется, но его можно получить. Для этого следует использовать специальную оберткуsave_resultдля посетителя; обертка сохранит полученное посетителем значение во внешнюю переменную, захваченную ссылкой. Результат посетителя инициализируется, когда возвращенныйрезультат посещенияявляется положительным. Смотрите следующий пример, где мы вычисляем хеш-значение на сохраненное значение.

struct hash_visitor
{
    typedef std::size_t result_type;
    result_type operator() (int val) const
    {
        std::size_t h = val;
        h = (h << 15) + h;
        h ^= (h >> 6) + (h << 7);
        return h;
    }
    result_type operator() (std::string const& val) const
    {
        std::size_t h = 0;
        for (std::string::const_iterator it = val.begin(), end = val.end(); it != end; ++it)
            h += *it;
        h = (h << 15) + h;
        h ^= (h >> 6) + (h << 7);
        return h;
    }
};
void hash_value(logging::attribute_value const& attr)
{
    // Define the set of expected types of the stored value
    typedef boost::mpl::vector< int, std::string > types;
    // Apply our visitor
    std::size_t h = 0;
    logging::visitation_result result = logging::visit< types >(attr, logging::save_result(hash_visitor(), h));
    // Check the result
    if (result)
        std::cout << "Visitation succeeded, hash value: " << h << std::endl;
    else
        std::cout << "Visitation failed" << std::endl;
}

См. полный код.

[Tip]Tip

При отсутствии состояния по умолчанию для результата посетителя удобно использоватьBoost.Optionalдля обертывания возвращенного значения.факультативныйбудет инициализирован с результатом посетителя, если посещение увенчается успехом. В случае, если посетитель является полиморфным (т.е. у него разные типы результатов в зависимости от типа аргумента)Для получения полученного значения может быть использован вариант. Также стоит использовать пустой тип, такой какбустер::пустой, чтобы указать неинициализированное состояниевариант.

Как уже упоминалось, посещение может также применяться к записям журналов и наборам значений атрибутов. Синтаксис одинаков, за исключением того, что имя атрибута также должно быть указано. Алгоритмпосещенияпопытается найти значение атрибута по имени, а затем применить посетителя к найденному элементу.

void hash_value(logging::record_view const& rec, logging::attribute_name name)
{
    // Define the set of expected types of the stored value
    typedef boost::mpl::vector< int, std::string > types;
    // Apply our visitor
    std::size_t h = 0;
    logging::visitation_result result = logging::visit< types >(name, rec, logging::save_result(hash_visitor(), h));
    // Check the result
    if (result)
        std::cout << "Visitation succeeded, hash value: " << h << std::endl;
    else
        std::cout << "Visitation failed" << std::endl;
}

Кроме того, для удобстваатрибут_значениеимеет способ под названиемпосещениес тем же значением, что и свободная функция, применяемая к значению атрибута.

#include <boost/log/attributes/value_extraction_fwd.hpp>
#include <boost/log/attributes/value_extraction.hpp>

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

void print_value(logging::attribute_value const& attr)
{
    // Extract a reference to the stored value
    logging::value_ref< int > val = logging::extract< int >(attr);
    // Check the result
    if (val)
        std::cout << "Extraction succeeded: " << val.get() << std::endl;
    else
        std::cout << "Extraction failed" << std::endl;
}

См. полный код.

В этом примере мы ожидаем, что значение атрибута будет иметь сохраненный типint. Функцияизвлеченияпытается извлечь ссылку на сохраненное значение и возвращает заполненныйзначение_refобъект, если это удается.

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

void print_value_multiple_types(logging::attribute_value const& attr)
{
    // Define the set of expected types of the stored value
    typedef boost::mpl::vector< int, std::string > types;
    // Extract a reference to the stored value
    logging::value_ref< types > val = logging::extract< types >(attr);
    // Check the result
    if (val)
    {
        std::cout << "Extraction succeeded" << std::endl;
        switch (val.which())
        {
        case 0:
            std::cout << "int: " << val.get< int >() << std::endl;
            break;
        case 1:
            std::cout << "string: " << val.get< std::string >() << std::endl;
            break;
        }
    }
    else
        std::cout << "Extraction failed" << std::endl;
}

Обратите внимание, что мы использовали, которыйметод обратной ссылки на отправку между возможными типами. Способ возвращает индекс типа в последовательноститипов. Также обратите внимание, что методgetтеперь принимает явный параметр шаблона для выбора эталонного типа для приобретения; естественно, этот тип должен соответствовать фактическому упомянутому типу, что оправдано утверждением переключателя / регистра в нашем случае.

Посещение ценности также поддерживается объектомvalue_ref. Вот как мы вычисляем хеш-значение из извлеченного значения:

struct hash_visitor
{
    typedef std::size_t result_type;
    result_type operator() (int val) const
    {
        std::size_t h = val;
        h = (h << 15) + h;
        h ^= (h >> 6) + (h << 7);
        return h;
    }
    result_type operator() (std::string const& val) const
    {
        std::size_t h = 0;
        for (std::string::const_iterator it = val.begin(), end = val.end(); it != end; ++it)
            h += *it;
        h = (h << 15) + h;
        h ^= (h >> 6) + (h << 7);
        return h;
    }
};
void hash_value(logging::attribute_value const& attr)
{
    // Define the set of expected types of the stored value
    typedef boost::mpl::vector< int, std::string > types;
    // Extract the stored value
    logging::value_ref< types > val = logging::extract< types >(attr);
    // Check the result
    if (val)
        std::cout << "Extraction succeeded, hash value: " << val.apply_visitor(hash_visitor()) << std::endl;
    else
        std::cout << "Extraction failed" << std::endl;
}

Наконец, как и при посещении ценности, извлечение ценности также может применяться к записям журнала и наборам значений атрибутов.

void hash_value(logging::record_view const& rec, logging::attribute_name name)
{
    // Define the set of expected types of the stored value
    typedef boost::mpl::vector< int, std::string > types;
    // Extract the stored value
    logging::value_ref< types > val = logging::extract< types >(name, rec);
    // Check the result
    if (val)
        std::cout << "Extraction succeeded, hash value: " << val.apply_visitor(hash_visitor()) << std::endl;
    else
        std::cout << "Extraction failed" << std::endl;
}

Кроме того, библиотека предоставляет два специальных варианта функцииэкстракта:экстракт_or_throwиэкстракт_or_default. Как следует из названия, функции обеспечивают различное поведение в случае, если значение атрибута не может быть извлечено. Первый бросает исключение, если значение не может быть извлечено, а второй возвращает значение по умолчанию.

[Warning]Warning

Следует соблюдать осторожность при выполнении функцииextract_or_default. Функция принимает значение по умолчанию, принимается постоянной ссылкой, и эта ссылка в конечном итоге может быть возвращена изextract_or_default. Если временный объект используется для значения по умолчанию, пользователь должен убедиться, что результатextract_or_defaultсохраняется по значению, а не по ссылке. В противном случае сохраненная ссылка может зависнуть при уничтожении временной.

Аналогичнопосетите, классатрибут_значениеимеет способы, названныеэкстракт,экстракт_or_throwиэкстракт_or_defaultс тем же значением, что и соответствующие свободные функции, применяемые к значению атрибута.

#include <boost/log/attributes/scoped_attribute.hpp>

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

BOOST_LOG_SCOPED_LOGGER_ATTR(logger, attr_name, attr);
BOOST_LOG_SCOPED_THREAD_ATTR(attr_name, attr);

Первый макрос регистрирует специфический атрибут источника врегистраторерегистраторе объекта. Имя атрибута и сам атрибут даны в аргументахattr_nameиattr. Второй макрос делает то же самое, но атрибут регистрируется для текущего потока в ядре для регистрации (что не требует регистратора).

[Note]Note

Если атрибут с тем же названием уже зарегистрирован в ядре logger/logging, макросы не будут переопределять существующий атрибут и в конечном итоге не будут иметь никакого эффекта. См.Обоснованиедля более подробного объяснения причин такого поведения.

Пример использования следующий:

BOOST_LOG_DECLARE_GLOBAL_LOGGER(my_logger, src::logger_mt)
void foo()
{
    // This log record will also be marked with the "Tag" attribute,
    // whenever it is called from the A::bar function.
    // It will not be marked when called from other places.
    BOOST_LOG(get_my_logger()) << "A log message from foo";
}
struct A
{
    src::logger m_Logger;
    void bar()
    {
        // Set a thread-wide markup tag.
        // Note the additional parentheses to form a Boost.PP sequence.
        BOOST_LOG_SCOPED_THREAD_ATTR("Tag",
            attrs::constant< std::string >("Called from A::bar"));
        // This log record will be marked
        BOOST_LOG(m_Logger) << "A log message from A::bar";
        foo();
    }
};
int main(int, char*[])
{
    src::logger lg;
    // Let's measure our application run time
    BOOST_LOG_SCOPED_LOGGER_ATTR(lg, "RunTime", attrs::timer());
    // Mark application start.
    // The "RunTime" attribute should be nearly 0 at this point.
    BOOST_LOG(lg) << "Application started";
    // Note that no other log records are affected by the "RunTime" attribute.
    foo();
    A a;
    a.bar();
    // Mark application ending.
    // The "RunTime" attribute will show the execution time elapsed.
    BOOST_LOG(lg) << "Application ended";
    return 0;
}

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

BOOST_LOG_SCOPED_LOGGER_TAG(logger, tag_name, tag_value);
BOOST_LOG_SCOPED_THREAD_TAG(tag_name, tag_value);

Макросы эффективно обертываются вокругBOOST_LOG_SCOPED_LOGGER_ATTRиBOOST_LOG_SCOPED_THREAD_ATTRсоответственно. Например, атрибут «Tag» из приведенного выше примера может быть зарегистрирован следующим образом:

BOOST_LOG_SCOPED_THREAD_TAG("Tag", "Called from A::bar");
[Warning]Warning

При использовании атрибутов с охватом убедитесь, что атрибут с охватом не изменен в наборе атрибутов, в котором он был зарегистрирован. Например, не следует очищать или переустанавливать набор атрибутов регистратора, если в нем зарегистрированы атрибуты, специфичные для регистратора. В противном случае программа может рухнуть. Эта проблема особенно важна в многопоточном приложении, когда один поток может не знать, есть ли атрибуты в регистраторе или нет. Будущие выпуски могут решить это ограничение, но в настоящее время атрибут должен оставаться нетронутым до тех пор, пока не будет зарегистрирован при выходе из сферы действия.

Хотя описанные макросы предназначены для того, чтобы быть основным интерфейсом для функциональности, существует также интерфейс C++. Это может быть полезно, если пользователь решает разработать свои собственные макросы, которые не могут быть основаны на существующих.

Любое примечательное свойство прикрепляется к общему сторожевому объекту типаscoped_attribute. Пока существует часовой, атрибут регистрируется. Существует несколько функций, которые создают часовые для атрибутов источника или потока:

// Source-specific scoped attribute registration
template< typename LoggerT >
[unspecified] add_scoped_logger_attribute(
    LoggerT& l,
    attribute_name const& name,
    attribute const& attr);
// Thread-specific scoped attribute registration
template< typename CharT >
[unspecified] add_scoped_thread_attribute(
    attribute_name const& name,
    attribute const& attr);

Объект типаscoped_attributeспособен прикреплять результаты каждой из этих функций к своей конструкции. Например,BOOST_LOG_SCOPED_LOGGER_ATTRlg,"RunTime",attrs::таймер() может быть примерно расширен до этого:

attrs::scoped_attribute sentry =
    attrs::add_scoped_logger_attribute(lg, "RunTime", attrs::timer());

PrevUpHomeNext

Статья Attributes раздела 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:13:56/0.04253101348877/1