Commit 8780f406 authored by Johan Ström's avatar Johan Ström

Add support for multiple logging "channels" with individual max level (c++)

parent 81126ea8
Pipeline #443 passed with stage
in 2 minutes and 45 seconds
......@@ -173,9 +173,13 @@ void AgoApp::setupLogging() {
else
level_str = getConfigOption("log_level", "info", ExtraConfigNameList("system"));
std::map<std::string, std::string> perChannelLevels = getConfigSection("loggers", ExtraConfigNameList("system"));
try {
logLevel = log_container::getLevel(level_str);
log_container::setCurrentLevel(logLevel);
auto channeLevels = log_container::getLevels(perChannelLevels);
log_container::setCurrentLevel(logLevel, channeLevels);
}catch(std::runtime_error &e) {
throw ConfigurationError(e.what());
}
......
......@@ -9,18 +9,12 @@
namespace agocontrol {
namespace log {
static AGO_LOGGER_IMPL default_inst;
typedef std::map<std::string, int> str_int_map;
static str_int_map syslog_facilities;
static std::vector<std::string> syslog_facility_names;
static std::vector<std::string> log_levels;
/* Static global accessor */
AGO_LOGGER_IMPL & log_container::get() {
return default_inst;
}
void init_static() {
if(log_levels.empty()) {
// Same order as severity_level
......@@ -86,6 +80,7 @@ const std::vector<std::string>& log_container::getSyslogFacilities() {
init_static();
return syslog_facility_names;
}
severity_level log_container::getLevel(const std::string &level) {
init_static();
std::string ulevel(boost::to_upper_copy(level));
......@@ -99,6 +94,14 @@ severity_level log_container::getLevel(const std::string &level) {
throw std::runtime_error("Invalid log level '" + level + "'");
}
std::map<std::string, severity_level> log_container::getLevels(const std::map<std::string, std::string>& src) {
std::map<std::string, severity_level> result;
for(auto i = src.cbegin(); i != src.cend(); i++) {
result[i->first] = getLevel(i->second);
}
return result;
}
const std::string& log_container::getLevel(severity_level level) {
init_static();
if(level >= log_levels.size()) {
......
......@@ -63,7 +63,7 @@ public:
/**
* Changes the severity setting of the logger
*/
static void setCurrentLevel(severity_level lvl);
static void setCurrentLevel(severity_level minOutputLevel, const std::map<std::string, severity_level>& channelLevels);
/**
* Changes to console output
......@@ -80,15 +80,17 @@ public:
/* Returns a vector of all supported syslog facitliy names */
static const std::vector<std::string>& getSyslogFacilities() ;
/* Translate level string to internal level. Returns -1 on invalid value */
/* Translate level string to internal level. Raises exception on invalid value. */
static severity_level getLevel(const std::string &level);
/* Translate a key->level map to internal levels. Raises exception on invalid value. */
static std::map<std::string, severity_level> getLevels(const std::map<std::string, std::string>& src);
/* Translate internal level to string. Throws exception on invalid value */
static const std::string & getLevel(severity_level lvl);
/* Returns a vector with all levels, indexed identical to severity_level */
static const std::vector<std::string> & getLevels();
};
} /* namespace log */
......
......@@ -56,6 +56,10 @@ record_pump::~record_pump()
static AGO_LOGGER_IMPL default_inst;
AGO_LOGGER_IMPL & log_container::get() {
return default_inst;
}
void log_container::setOutputConsole() {
get().setSink(boost::shared_ptr<log_sink>( new console_sink() ) );
......@@ -72,11 +76,11 @@ void log_container::initDefault() {
return;
inited = true;
setCurrentLevel(AGO_DEFAULT_LEVEL);
get().setLevel(AGO_DEFAULT_LEVEL);
// Default inited with console sink
}
void log_container::setCurrentLevel(severity_level lvl) {
void log_container::setCurrentLevel(severity_level lvl, const std::map<std::string, severity_level>& ignored) {
get().setLevel(lvl);
}
......
......@@ -160,4 +160,18 @@ class simple_logger {
#define AGO_ERROR() AGO_LOG_SEV(AGO_GET_LOGGER, ::agocontrol::log::error)
#define AGO_FATAL() AGO_LOG_SEV(AGO_GET_LOGGER, ::agocontrol::log::fatal)
// Named loggers are not supported; automatically logs to default logger.
// Usage is often "static AGO_LOGGER(..)" though so must declare something.
#define AGO_LOGGER(name) AGO_LOGGER_ALIAS(name, name)
#define AGO_LOGGER_ALIAS(name, alias) int __attribute__((unused)) __not_used_ ## name
#define AGOL_TRACE(name) AGO_LOG_SEV(AGO_GET_LOGGER, ::agocontrol::log::trace)
#define AGOL_DEBUG(name) AGO_LOG_SEV(AGO_GET_LOGGER, ::agocontrol::log::debug)
#define AGOL_INFO(name) AGO_LOG_SEV(AGO_GET_LOGGER, ::agocontrol::log::info)
#define AGOL_WARNING(name) AGO_LOG_SEV(AGO_GET_LOGGER, ::agocontrol::log::warning)
#define AGOL_ERROR(name) AGO_LOG_SEV(AGO_GET_LOGGER, ::agocontrol::log::error)
#define AGOL_FATAL(name) AGO_LOG_SEV(AGO_GET_LOGGER, ::agocontrol::log::fatal)
#endif
......@@ -38,6 +38,8 @@ namespace attrs = boost::log::attributes;
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level);
BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", std::string)
// The formatting logic for the severities
template< typename CharT, typename TraitsT >
......@@ -66,6 +68,10 @@ struct ago_log_exception_handler
}
};
static AGO_LOGGER_IMPL default_inst(boost::log::keywords::channel = "app");
AGO_LOGGER_IMPL & log_container::get() {
return default_inst;
}
void log_container::initDefault() {
if(inited)
......@@ -73,9 +79,8 @@ void log_container::initDefault() {
inited = true;
logging::add_common_attributes();
setOutputConsole();
setCurrentLevel(AGO_DEFAULT_LEVEL);
setCurrentLevel(AGO_DEFAULT_LEVEL, std::map<std::string, severity_level>());
// Setup exception handler
logging::core::get()->set_exception_handler(logging::make_exception_handler<
......@@ -85,10 +90,27 @@ void log_container::initDefault() {
}
void log_container::setCurrentLevel(severity_level lvl) {
/**
* Configure logging levels.
*
* minOutputLevel controls overall minimum level, i.e. if set to INFO nothing lower than INFO is logged.
* In addition, it's possible to configure minimum levels for different channels, via the channelLevels map.
* I.e. if "mqtt" channel is ocnfigured with INFO, but minOutputLevel is TRACE, then we still won't see anything
* lower than INFO from mqtt.
* If it's instead set to TRACE, and we have minOutputLevel to DEBUG, we will still only see DEBUG from that channel.
*/
void log_container::setCurrentLevel(severity_level minOutputLevel, const std::map<std::string, severity_level>& channelLevels) {
typedef expr::channel_severity_filter_actor< std::string, severity_level > severity_filter;
severity_filter min_severity = expr::channel_severity_filter(channel, severity);
for(auto i = channelLevels.cbegin(); i != channelLevels.cend(); i++) {
min_severity[i->first] = i->second;
}
min_severity.set_default(true);
boost::log::core::get()->set_filter
(
::agocontrol::log::severity >= lvl
min_severity && ::agocontrol::log::severity >= minOutputLevel
);
}
......@@ -126,8 +148,9 @@ void log_container::setOutputConsole() {
(
expr::stream
<< expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d %H:%M:%S.%f")
<< " [" << expr::attr< attrs::current_thread_id::value_type > ("ThreadID") << "] "
<<" [" << std::setw(7) << severity << std::setw(0) << "] "
<< " [" << expr::attr< attrs::current_thread_id::value_type > ("ThreadID") << "]"
<< " [" << std::setw(6) << std::left << severity << std::setw(0)
<< " : " << std::setw(5) << std::right << channel << std::setw(0) << "] "
<< expr::smessage
);
......
......@@ -9,6 +9,9 @@
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/channel_feature.hpp>
#include <boost/log/sources/severity_channel_logger.hpp>
#define AGO_TRACE() BOOST_LOG_SEV(AGO_GET_LOGGER, ::agocontrol::log::trace)
#define AGO_DEBUG() BOOST_LOG_SEV(AGO_GET_LOGGER, ::agocontrol::log::debug)
......@@ -17,6 +20,17 @@
#define AGO_ERROR() BOOST_LOG_SEV(AGO_GET_LOGGER, ::agocontrol::log::error)
#define AGO_FATAL() BOOST_LOG_SEV(AGO_GET_LOGGER, ::agocontrol::log::fatal)
#define AGO_LOGGER_IMPL boost::log::sources::severity_logger_mt<agocontrol::log::severity_level>
#define AGOL_TRACE(name) BOOST_LOG_SEV(logger_ ## name, ::agocontrol::log::trace)
#define AGOL_DEBUG(name) BOOST_LOG_SEV(logger_ ## name, ::agocontrol::log::debug)
#define AGOL_INFO(name) BOOST_LOG_SEV(logger_ ## name, ::agocontrol::log::info)
#define AGOL_WARNING(name) BOOST_LOG_SEV(logger_ ## name, ::agocontrol::log::warning)
#define AGOL_ERROR(name) BOOST_LOG_SEV(logger_ ## name, ::agocontrol::log::error)
#define AGOL_FATAL(name) BOOST_LOG_SEV(logger_ ## name, ::agocontrol::log::fatal)
#define AGO_LOGGER_IMPL boost::log::sources::severity_channel_logger_mt<agocontrol::log::severity_level, std::string>
#define AGO_LOGGER(name) AGO_LOGGER_ALIAS(name, #name)
#define AGO_LOGGER_ALIAS(name, alias) boost::log::sources::severity_channel_logger_mt<agocontrol::log::severity_level, std::string> \
logger_ ## name (boost::log::keywords::channel = alias)
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment