I have some trivial logging:
BOOST_LOG_TRIVIAL(trace) << make_trace_record();
Now make_trace_record
is a somewhat expensive function to call (don't ask why, it's complicated). I want to call it only if the log currently passes filtering. How can I do that? I don't see a way to call the severity filter explicitly.
Boost.Log filters beforehand; therefore, make_trace_record()
will not be called if the severity is not high enough.
In order to set the severity filter for the trivial logger, call:
boost::log::core::get()->set_filter(
boost::log::trivial::severity >= boost::log::trivial::...
);
For instance, the following example outputs 1
, showing that expensive()
is only called once:
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;
}
Prints:
[2018-05-21 14:33:47.327507] [0x00007eff37aa1740] [error] 1
1
For those wondering how it works, take a look to: How does the "lazy evaluation" of Boost Log's trivial loggers work?
Acorn's answer correctly points out that Boost.Log macros already implement conditional execution of the streaming expression. This behavior is documented in the Tutorial.
I will add that you can generate log records manually, avoiding the macros. An example is given here:
logging::record rec = lg.open_record();
if (rec)
{
logging::record_ostream strm(rec);
strm << "Hello, World!";
strm.flush();
lg.push_record(boost::move(rec));
}
This can be useful if log message formatting is complicated and doesn't fit easily in a streaming expression.
I would do this with an intermediate class who's ostream operator lazily calls your function.
Something like this:
#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(); });
}