2015-12-18 2 views
1

Я изучаю Boost.Log какое-то время, и я считаю, что сейчас настало время перевести мою базу кода с log4cxx на Boost.Log. Я считаю, что дизайн и внедрение Boost.Log значительно улучшат обслуживание и использование кода. Я знаю, что Boost.Log часто задает page that saysИспользуйте канал hiearchy для Boost.Log для фильтрации серьезности и раковины

Что касается иерархических регистраторов, то в этой библиотеке нет необходимости в этой функции. Одним из основных преимуществ, которые он предоставляет в log4j, является определение приложений (поглотителей, с точки зрения этой библиотеки), в которых запись журнала будет . Эта библиотека достигает того же результата путем фильтрации.

Я понимаю концептуальную эквивалентность и не пытаюсь сделать Boost.Log в log4j/log4cxx. Скорее мой вопрос: как я могу использовать Boost.Log для получения той же функциональности, которую я сейчас использую в log4cxx? В частности, я хочу установить пороговые значения серьезности и приемники для определенных узлов в источнике журнала или иерархии каналов. Например, у меня есть источники каротажа, организованные libA.moduleB.componentC.logD с уровнями в иерархии, разделенными точками .. Используя log4cxx, можно задать общий порог libA для INFO с более конкретным регистратором, libA.moduleB, имеющий порог DEBUG.

libA.threshold=INFO 
libA.moduleB.threshold=DEBUG 

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

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

Искренне благодарю вас за ваши комментарии.

ответ

9

В блоках Boost.Log (объекты, которые записывают файлы журналов) и регистраторы (объекты, через которые ваше приложение испускает записи журнала) напрямую не подключены, и любой приемник может получать сообщение журнала из любого регистратора. Для того, чтобы записи из определенных журналов появлялись только в частности приемниках, вам придется организовать фильтры в раковинах, чтобы ненужные записи были подавлены для приемников, которые не должны их получать и передавать другим. Чтобы отличать записи от разных регистраторов, регистраторы должны добавлять разные атрибуты к каждой сделанной им записи. Обычно это достигается с помощью channels - регистраторы свяжут атрибут канала, который может использоваться для идентификации регистратора в фильтрах, форматировщиках или приемниках. Каналы могут быть combined с другими атрибутами, такими как уровни серьезности. Следует отметить, что каналы и уровни серьезности ортогональны, и любой канал может иметь записи любого уровня. Значения различных атрибутов анализируются отдельно в фильтрах.

Так, например, если вы хотите записать записи из канала A в файл A.log, а с канала B - в B.log, вы должны создать два приемника - по одному для каждого файла и установить их фильтрует соответственно.

BOOST_LOG_ATTRIBUTE_KEYWORD(a_severity, "Severity", severity_level) 
BOOST_LOG_ATTRIBUTE_KEYWORD(a_channel, "Channel", std::string) 

logging::add_file_log(
    keywords::file_name = "A.log", 
    keywords::filter = a_channel == "A"); 

logging::add_file_log(
    keywords::file_name = "B.log", 
    keywords::filter = a_channel == "B"); 

Смотрите документацию о defining attribute keywords и convenience setup functions. Теперь вы можете создавать регистраторы для каждого канала, а записи журналов будут направляться в приемники с помощью фильтров.

typedef src::severity_channel_logger< severity_level, std::string > logger_type; 

logger_type lg_a(keywords::channel = "A"); 
logger_type lg_b(keywords::channel = "B"); 

BOOST_LOG_SEV(lg_a, info) << "Hello, A.log!"; 
BOOST_LOG_SEV(lg_b, info) << "Hello, B.log!"; 

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

Однако здесь есть две проблемы.Во-первых, библиотека не знает природы канала и считает ее просто непрозрачной. Он не знает иерархии каналов, поэтому «A» и «A.bb» считаются разными и не связанными каналами. Во-вторых, настройка таких фильтров, как описано выше, может быть затруднена, если вы хотите записать несколько каналов в один файл (например, «A» и «A.bb»). Все станет еще сложнее, если вы захотите разного уровня серьезности для разных каналов.

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

Существует несколько способов создания фильтра, но это сводится к написанию функции, которая принимает значения атрибута из записей журнала и возвращает true, если эта запись прошла фильтр и false в противном случае. Возможно, самый простой способ показан в Tutorial, см. Пример с phoenix::bind от Boost.Phoenix.

bool my_filter(
    logging::value_ref< severity_level, tag::a_severity > const& level, 
    logging::value_ref< std::string, tag::a_channel > const& channel, 
    channel_hierarchy const& thresholds) 
{ 
    // See if the log record has the severity level and the channel attributes 
    if (!level || !channel) 
     return false; 

    std::string const& chan = channel.get(); 

    // Parse the channel string, look for it in the hierarchy 
    // and find out the severity threshold for this channel 
    severity_level threshold = thresholds.find(chan); 

    return level.get() >= threshold; 
} 

Теперь настройка поглотителей изменятся, как это использовать ваш новый фильтр:

logging::add_file_log(
    keywords::file_name = "A.log", 
    keywords::filter = phoenix::bind(&my_filter, a_severity.or_none(), a_channel.or_none(), hierarchy_A)); 

logging::add_file_log(
    keywords::file_name = "B.log", 
    keywords::filter = phoenix::bind(&my_filter, a_severity.or_none(), a_channel.or_none(), hierarchy_B)); 

Здесь hierarchy_A и hierarchy_B являются вашими структурами данных, используемых для хранения критичности пороговых значений для различных каналов для два лога файлы.

+0

Спасибо за ваш ответ. Я ценю вашу помощь, чтобы начать меня. Иерархия каналов важна для меня, поэтому мне придется идти с дополнительной сложностью. С контуром, который вы мне дали, мне кажется, что моя проблема сводится к написанию структур данных и логики для поддержки фильтров порога и приемника с дочерними узлами, наследующими от родительских узлов. С log4j они подчеркивают, как у них есть оптимальная схема для этого. Знаете ли вы, выполнил ли кто-то подобную схему с помощью библиотеки Boost.Log? – Phil

+0

Нет, я не думаю, что знаю, кто это делает. Однако создание структуры данных для порогов серьезности выглядит не так сложно - вы можете реализовать ее с помощью множества вложенных 'std :: map' /' std :: unordered_map' или с Boost.PropertyTree (http: // www. boost.org/doc/libs/1_60_0/doc/html/property_tree.html), который уже имеет сериализацию/десериализацию в/из текста. –

+0

Как определяется channel_hierarchy? –