Search code examples
c++boostboost-logboost-logging

Boost.Log - Log messages are unexpectedly filtered out


I am trying to create filter by configurable severity level. I have written following filter class:

class FilterBySeverity
{
public:
    FilterBySeverity(boost::log::trivial::severity_level logLevel) :
        m_logLevel(logLevel),
        m_severityAttributeName("Severity")
    {
    }

    bool operator()(const boost::log::attribute_value_set& attrs) const noexcept
    {
        auto it = attrs.find(m_severityAttributeName);
        if (it == attrs.end()) return true;
        return it->second.extract<int>() >= m_logLevel;
    }

private:
    const boost::log::trivial::severity_level m_logLevel;
    const boost::log::attribute_name m_severityAttributeName;
};

and then I am initializing log as follows:

auto sink = boost::log::add_console_log(std::cout);
sink->set_filter(FilterBySeverity(logOptions.m_severity));
sink->locked_backend()->auto_flush(true);

Then I am making test output:

BOOST_LOG_TRIVIAL(info) << "Logging started.";

But I can't see my message. But when I comment out call to set_filter(), message appears. Value of the logOptions.m_severity is 0, i.e. all messages should be allowed. Tried to set breakpoint in the operator() and check what's going on - it seems to work correctly. What I am doing wrong?


Solution

  • The problem is the incorrect attribute value type you're trying to extract. You explicitly specify the type as int while the logger used by BOOST_LOG_TRIVIAL uses boost::log::trivial::severity_level. The result of the extract call in this case is an empty value_ref instance, which returns false on any comparison operators.

    A better and more correct way to write the filter is to use attribute keywords, which take care of both the attribute names and their value types. Since you're using the trivial logging API, there is already a keyword defined by the library that corresponds to an attribute named "Severity" that has values of type boost::log::trivial::severity_level: boost::log::trivial::severity.

    bool operator()(const boost::log::attribute_value_set& attrs) const noexcept
    {
        // returns an empty value_ref if the attribute value is not found
        // or has a different type
        auto sev = attrs[boost::log::trivial::severity];
        return !sev || sev >= m_logLevel;
    }