Проверить фильтр boost::log явно?

У меня есть тривиальное ведение журнала:

BOOST_LOG_TRIVIAL(trace) << make_trace_record();

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


person n. 1.8e9-where's-my-share m.    schedule 15.05.2018    source источник


Ответы (3)


Boost.Log фильтрует заранее; поэтому make_trace_record() не будет вызываться, если серьезность недостаточно высока.

Чтобы установить фильтр серьезности для тривиального регистратора, вызовите:

boost::log::core::get()->set_filter(
    boost::log::trivial::severity >= boost::log::trivial::...
);

Например, следующий пример выводит 1, показывая, что expensive() вызывается только один раз:

Жить на Coliru

#include <iostream>

#include <boost/log/expressions.hpp>
#include <boost/log/trivial.hpp>

int count = 0;

int expensive()
{
    return ++count;
}

int main()
{
    boost::log::core::get()->set_filter(
        boost::log::trivial::severity >= boost::log::trivial::warning
    );

    BOOST_LOG_TRIVIAL(error) << expensive();
    BOOST_LOG_TRIVIAL(info) << expensive();

    std::cout << count << '\n';

    return 0;
}

Отпечатки:

[2018-05-21 14:33:47.327507] [0x00007eff37aa1740] [error]   1
1

Для тех, кто интересуется, как это работает, взгляните на: ">Как работает ленивая оценка тривиальных логгеров Boost Log?

person Acorn    schedule 15.05.2018
comment
Это довольно впечатляет. И неожиданно :) Теперь я хочу поместить это в github.com/andreasfertig/cppinsights, чтобы понять, как - person sehe; 15.05.2018
comment
Вау, это действительно неожиданно. Это работает, потому что BOOST_LOG_TRIVIAL() расширяется не до выражения, а до частичного оператора if. - person n. 1.8e9-where's-my-share m.; 15.05.2018
comment
@n.m.: На самом деле, он расширяется в цикл for, но на самом деле трюк тот же (см. Связанный вопрос, который я разместил). - person Acorn; 15.05.2018

Acorn ответ правильно указывает, что макросы Boost.Log уже реализуют условное выполнение потоковой передачи выражение. Это поведение задокументировано в Учебник.

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

logging::record rec = lg.open_record();
if (rec)
{
    logging::record_ostream strm(rec);
    strm << "Hello, World!";
    strm.flush();
    lg.push_record(boost::move(rec));
}

Это может быть полезно, если форматирование сообщений журнала сложное и не вписывается в потоковое выражение.

person Andrey Semashev    schedule 16.05.2018

Я бы сделал это с промежуточным классом, оператор ostream которого лениво вызывает вашу функцию.

Что-то вроде этого:

#include <type_traits>
#include <utility>
#include <ostream>
#include <iostream>


namespace detail
{
    // an ostreamable object that will stream out the result of a unary function object call
    template<class F>
    struct lazy_generator
    {
        void write(std::ostream& os) const
        {
            os << generator_();
        }

        friend std::ostream& operator<<(std::ostream& os, lazy_generator const& tr)
        {
            tr.write(os);
            return os;
        }

        F generator_;
    };
}

// construct a lazy_generator
template<class F>
auto lazy_trace(F&& f)
{
    return detail::lazy_generator<std::decay_t<F>>({std::forward<F>(f)});
}

// test
int main()
{
    extern std::string make_trace_record();

    // function pointer
    std::clog << lazy_trace(&make_trace_record);

    // function object
    std::clog << lazy_trace([](){ return make_trace_record(); });
}
person Richard Hodges    schedule 15.05.2018
comment
Я думал об этом, но это выглядит как излишество, и, к счастью, в этом нет необходимости. Оценка уже закорочена благодаря (небезопасным, но работающим) макросам boost. См. другой ответ. - person n. 1.8e9-where's-my-share m.; 15.05.2018