Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the "lazy evaluation" of Boost Log's trivial loggers work?

[Follows up Check boost::log filter explicitly? ]

The following example uses the trivial logger from Boost Log. It outputs 1, showing that expensive() is only called once. How does it work? Why is expensive() not called?

Live On 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;
}

Output:

[2018-05-21 14:33:47.327507] [0x00007eff37aa1740] [error]   1
1
like image 266
Acorn Avatar asked May 15 '18 15:05

Acorn


1 Answers

It works by using a bit of macro/preprocessor magic. The statements look indeed like a function call to some operator<<():

BOOST_LOG_TRIVIAL(warning) << expensive();

However, simplifying a lot, the macro works as if we had written something like:

if (level == warning)
    logger << expensive();

If you wanted to simplify that code to avoid writing all the time, you could define a macro like this:

#define LOG_WARNING if (level == warning) logger

And then we could use it as:

LOG_WARNING << expensive();

The actual BOOST_LOG_TRIVIAL macro ends up expanding into:

for (
    ::boost::log::record _boost_log_record_N =
        (::boost::log::trivial::logger::get()).open_record(
            (::boost::log::keywords::severity = ::boost::log::trivial::error)
        )
    ;
    !!_boost_log_record_N;
)
    ::boost::log::aux::make_record_pump(
        (::boost::log::trivial::logger::get()),
        _boost_log_record_N
    ).stream() << expensive();

As you see, depending on the !!_boost_log_record_N loop condition (which in turn depends on the result of open_record()), the body of the loop will be run zero or more times; which is the reason why expensive() is not always run.

like image 80
Acorn Avatar answered Oct 05 '22 12:10

Acorn