Joachim Pileborg Joachim Pileborg - 11 months ago 70
C++ Question

Set both severity and channel for each record

I am using the combined severity and channel logger to get some kind of scope to the logging output.

The problem is that I want to use a single logging object for my whole project, and therefore want to be able to set the channel for a specific record, and I am not able to set both severity and channel. I can set either or, but not both.

Example code:

#include <iostream>
#include <boost/log/trivial.hpp>
#include <boost/log/sources/severity_channel_logger.hpp>
#include <boost/log/utility/manipulators/add_value.hpp>
#include <boost/log/utility/setup/common_attributes.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>

namespace logging = boost::log;

using logger_type = logging::sources::severity_channel_logger_mt<logging::trivial::severity_level>;

int main()

using text_sink_type = logging::sinks::synchronous_sink<logging::sinks::text_ostream_backend>;
auto sink = boost::make_shared<text_sink_type>();

sink->locked_backend()->add_stream(boost::shared_ptr<std::ostream>(&std::clog, boost::null_deleter()));

<< logging::expressions::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d %H:%M:%S.%f") << " :: "
<< '[' << logging::trivial::severity << " - " << logging::expressions::attr<std::string>("Channel") << "] "
<< logging::expressions::smessage


logger_type logger;

auto rec = logger.open_record(logging::keywords::severity = logging::trivial::info);
if (rec)
// This do not work
rec.attribute_values()["Channel"] = logging::attributes::make_attribute_value(std::string{"bar"});

logging::record_ostream ros{rec};

// This do not work either
ros << logging::add_value("Channel", std::string{"foo"});

ros << "Some message";

The above code will output

2016-09-27 10:25:38.941645 :: [info - ] Some message

As seen, the channel name is not in the output.

I can easily set the channel name when opening the record:

auto rec = logger.open_record(logging::keywords::channel = std::string{"channel"});

But then I am not able to set the correct severity.

Is there a way to set both severity and channel for a single record? Or do I have to use multiple logger objects, one per channel?

Optionally I can easily create new logging objects for each output, but that seems excessive even for small amounts of logging.

Answer Source

open_record() takes a set of attributes. The latter is built via the overloaded comma operator. However, in order to suppress the interpretation of the comma as a function argument separator, you must add an extra pair of parentheses.

auto rec = logger.open_record( (logging::keywords::channel = std::string{"channel"}, logging::keywords::severity = logging::trivial::info) );