Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ How to set a severity filter on a Boost Global Logger

Tags:

c++

logging

boost

I've been trying for days now to create a Boost Global Logger for use throughout the application but I can't seem to get the severity level set in the Global Logger.

IMPORTANT:

Look below for Andrey's answer...it's labeled as step (a) and (b) but I'm still not getting it right!


Right out of the Boost Documentation here

...it would be more convenient to have one or several global loggers in order to easily access them in every place when needed. In this regard std::cout is a good example of such a logger.

The library provides a way to declare global loggers that can be accessed pretty much like std::cout. In fact, this feature can be used with any logger, including user-defined ones. Having declared a global logger, one can be sure to have a thread-safe access to this logger instance from any place of the application code. The library also guarantees that a global logger instance will be unique even across module boundaries. This allows employing logging even in header-only components that may get compiled into different modules.


Regardless of the macro you used to declare the logger, you can acquire the logger instance with the static get function of the logger tag:

src::severity_logger_mt< >& lg = my_logger::get();

I found out from the Boost Logger guru, Andrey, that my problem is the severity type mismatch.

You have instantiated severity_logger_mt with default template parameters, so the severity level attribute has type int. Your enum values are converted to int and sent to the logging core. You have not set up any sinks, so by default the default sink is used. The sink attempts to extract severity level attribute value from log records, but fails to do that because it expects the severity level to be of type boost::log::trivial::severity_level. After that failure the sink falls back to boost::log::trivial::severity_level::info severity.

If you want to use your enum for severity levels you have to:

------------------------------------ ( Now, here is the ANSWER !!!! ) ---------------------------------------

(a) specify it in the logger template parameters and

(b) set up a sink with a formatter that is aware of your enum.

But I can't figure out how to do this, because even after trying to follow his instructions the severity level looks like the sink is still falling back to the boost::log::trivial::severity_level::info severity. Can anyone help me figure out how to get the severity set correctly in my global logger? Here is the code:

HEADER

#include <boost/log/trivial.hpp>
#include <boost/log/sources/global_logger_storage.hpp>

enum severity_level
{
    normal,
    warning,
    error,
    critical
};

BOOST_LOG_GLOBAL_LOGGER(logger, boost::log::sources::severity_logger_mt< severity_level >)

CPP

#include "GlobalLogger.h"

#include <boost/log/expressions/formatters/date_time.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/core/null_deleter.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/make_shared.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/sinks.hpp>
#include <fstream>

namespace logging = boost::log;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace sinks = boost::log::sinks;
namespace attrs = boost::log::attributes;

bool onlyWarnings(const boost::log::attribute_value_set& set)
{
    return set["Severity"].extract<severity_level>() > 0;
}

void severity_and_message(const boost::log::record_view &view, boost::log::formatting_ostream &os)
{
    os << view.attribute_values()["Severity"].extract<severity_level>() << ": " <<
    view.attribute_values()["Message"].extract<std::string>();
}

BOOST_LOG_GLOBAL_LOGGER_INIT(logger, boost::log::sources::severity_logger_mt< severity_level >)
{
    boost::log::sources::severity_logger_mt< severity_level > logger;

    // add a text sink
    typedef sinks::asynchronous_sink<sinks::text_ostream_backend> text_sink;
    boost::shared_ptr<text_sink> sink = boost::make_shared<text_sink>();

    // add "console" output stream to our sink
    boost::shared_ptr<std::ostream> stream{&std::clog, boost::null_deleter{}};
    sink->locked_backend()->add_stream(stream);

    // specify the format of the log message
    sink->set_formatter(&severity_and_message);

    // just log messages with severity >= SEVERITY_THRESHOLD are written
    sink->set_filter(&onlyWarnings);

    // "register" our sink
    logging::core::get()->add_sink(sink);

    logging::add_common_attributes();

    return logger;
}

main.cpp

#include <iostream>

#include "GlobalLogger.h"

using namespace std;

int main() {
    boost::log::sources::severity_logger_mt<  severity_level >& lg = logger::get();
    BOOST_LOG_SEV(lg, severity_level::normal) << "note";
    BOOST_LOG_SEV(lg, severity_level::warning) << "warning";
    BOOST_LOG_SEV(lg, severity_level::critical) << "critical";

    return 0;
}

I found a better example 62.10. A macro to define a global logger and a working version in this SO question. But the working example does not use the get() method. So, after declaring the BOOST_LOG_GLOBAL_LOGGER, I was able to access log::get() but I still can't get it to recognize the severity.

like image 1000
Patricia Avatar asked Apr 21 '15 23:04

Patricia


1 Answers

I found Andrey, the Boost Log expert. To help others in the future, I am posting a link to our Sourceforge discussion. After much banging my head on my monitor, it took his explanaition and revisiting the working version in this SO question. But I finally got it working! YAY!!!

like image 111
Patricia Avatar answered Sep 30 '22 00:09

Patricia