3

I'm using trivial logging of boost::log library and I want to execute some code depending on currently set logger severity. This is needed for constructing of log message only if it will be outputted. But I cannot find the right way for querying severity. The code must be something like:

if (boost::log::trivial::severity <=
    boost::log::trivial::severity_level::trace)
{
  // construct log message
  BOOST_LOG_TRIVIAL(trace) << message;
}

In addition may be there is some way when I know that the message will be outputted to avoid double checking of severity and output it directly instead of using BOOST_LOG_TRIVIAL macro?

bobeff
  • 3,543
  • 3
  • 34
  • 62

2 Answers2

3

It doesn't work like that. You need to provide a filter function to boost::log::trivial as per the documentation:

http://www.boost.org/doc/libs/1_61_0/libs/log/doc/html/log/tutorial/trivial_filtering.html

void init()
{
    logging::core::get()->set_filter
    (
        // here they've used a constant but you could use a global or
        // a function
        logging::trivial::severity >= logging::trivial::info
    );
}

int main(int, char*[])
{
    init();

    BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
    BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
    BOOST_LOG_TRIVIAL(info) << "An informational severity message";
    BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
    BOOST_LOG_TRIVIAL(error) << "An error severity message";
    BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";

    return 0;
}

The object passed to logging::core::set_filter is of type boost::log::filter

You could just as easily write:

auto filt = logging::filter(logging::trivial::severity >= logging::trivial::info);
logging::core::get()->set_filter(filt);

filt is a lightweight function object whose job is to inspect the attributes sent to it and return whether or not all tests against those attributes return true. In this case there is only one test - logging::trivial::severity >= logging::trivial::info.

It is the job of the logger to construct the attribute set and pass it to boost::log::core when it wants to emit something.

The long and short of it is that you must track the logging level in your own variable. Here is one way:

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

namespace logging = boost::log;


int main(int, char*[])
{
    // track your own variable here
    logging::trivial::severity_level my_log_level = logging::trivial::trace;

    // with this filter
    auto filt = logging::filter(logging::trivial::severity >= my_log_level);
    logging::core::get()->set_filter(filt);

    BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
    BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
    BOOST_LOG_TRIVIAL(info) << "An informational severity message";
    BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
    BOOST_LOG_TRIVIAL(error) << "An error severity message";
    BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";

    // now you have control
    if (my_log_level <= logging::trivial::trace)
    {
        std::cout << "tracing\n";
    }


    return 0;
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • 1
    This doesn't answer the question. There must be some way to execute arbitrary code conditionally according to the severity. – bobeff Dec 14 '16 at 14:01
  • Will flesh out the answer. Unfortunately you assume incorrectly – Richard Hodges Dec 14 '16 at 14:09
  • @bobeff answer updated with example of how to track your own logging level – Richard Hodges Dec 14 '16 at 14:19
  • "The long and short of it is that you must track the logging level in your own variable." This seems like working solution. 10x. – bobeff Dec 14 '16 at 14:28
  • The filter copies `my_log_level`, so when you change it the filter will still use the old value. You can use `boost::phoenix::ref(my_log_level)` to make the filter refer to the variable, but you will have to ensure that the variable is accessed thread-safely. – Andrey Semashev Dec 15 '16 at 09:31
0

Here is an option which adds another layer of logging macros and wraps code to be called conditionally in a lambda function fed to those macros. The lambda function is evaluated only if the severity-level constraint is satisfied.

To the best of my understanding, this method is thread-safe, but my understanding of boost::log is...limited. I haven't tested in a multi-threaded environment.

 //g++ -std=gnu++11  -DBOOST_LOG_DYN_LINK main.cpp -lboost_log -lpthread -o lambda_demo                    

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

 namespace logging = boost::log;

 #define LOG_TRACE(ARG) BOOST_LOG_TRIVIAL(trace) << ARG;
 #define LOG_INFO(ARG) BOOST_LOG_TRIVIAL(info) << ARG;

 const std::string complicated_function(const std::string &message)
 {
     std::cout << "\nInside complicated_function.\n" << std::flush;
     return "Returning from complicated_function (" + message + ").\n";
 }

 int main(int, char*[])
 {
     std::cout << "\n" << complicated_function("called from std::cout") << "\n" << std::flush;

     BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
     BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
     BOOST_LOG_TRIVIAL(info) << "An informational severity message";
     BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
     BOOST_LOG_TRIVIAL(error) << "An error severity message";
     BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message\n";

     LOG_TRACE ("Coming up: a trace message with a lambda function:");

     LOG_TRACE (
         [=]() {
             return complicated_function("(called from LOG_TRACE");
         }()
         );

     logging::core::get()->set_filter
         (
             logging::trivial::severity >= logging::trivial::info
             );

     BOOST_LOG_TRIVIAL(trace) << "After setting filter, another trace severity message";
     BOOST_LOG_TRIVIAL(debug) << "After setting filter, another debug severity message";
     BOOST_LOG_TRIVIAL(info) << "After setting filter, another informational severity message";
     BOOST_LOG_TRIVIAL(warning) << "After setting filter, another warning severity message";
     BOOST_LOG_TRIVIAL(error) << "After setting filter, anothern error severity message";
     BOOST_LOG_TRIVIAL(fatal) << "After setting filter, another fatal severity message\n";

     LOG_TRACE ("Coming up: a trace message with a lambda function:");
     LOG_TRACE (
         [=]() {
             return complicated_function("called from LOG_TRACE");
         }()
         );

     LOG_INFO ("Coming up: an info message with a lambda function:");
     LOG_INFO (
         [=]() {
             return complicated_function("called from LOG_INFO");
         }()
         );

     return 0;
 }