diff options
Diffstat (limited to 'gnuradio-runtime/lib/logger.cc')
-rw-r--r-- | gnuradio-runtime/lib/logger.cc | 444 |
1 files changed, 89 insertions, 355 deletions
diff --git a/gnuradio-runtime/lib/logger.cc b/gnuradio-runtime/lib/logger.cc index 4721571119..64219d6a8e 100644 --- a/gnuradio-runtime/lib/logger.cc +++ b/gnuradio-runtime/lib/logger.cc @@ -1,6 +1,7 @@ /* -*- c++ -*- */ /* * Copyright 2012 Free Software Foundation, Inc. + * Copyright 2021 Marcus Müller * * This file is part of GNU Radio * @@ -8,410 +9,143 @@ * */ -/******************************************************************************* - * Author: Mark Plett - * Description: - * The gr_log module wraps the log4cpp library for logging in gnuradio. - *******************************************************************************/ - +#include <spdlog/common.h> #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <gnuradio/logger.h> - #include <gnuradio/prefs.h> -#include <log4cpp/FileAppender.hh> -#include <log4cpp/OstreamAppender.hh> -#include <log4cpp/PatternLayout.hh> -#include <log4cpp/PropertyConfigurator.hh> -#include <log4cpp/RollingFileAppender.hh> -#include <boost/format.hpp> -#include <boost/thread.hpp> +#include <spdlog/async.h> +#include <spdlog/sinks/basic_file_sink.h> +#include <spdlog/sinks/dist_sink.h> +#include <spdlog/sinks/stdout_color_sinks.h> +#include <spdlog/spdlog.h> -#include <algorithm> -#include <filesystem> -#include <iostream> #include <memory> -#include <stdexcept> namespace gr { - -bool logger_config::logger_configured(false); - -/************************ BEGIN LOG4CPP HELPERS ***********************/ -/* Logger config class. This is a singleton that controls how - * log4cpp is configured If watch_period>0 a thread is started to - * watch the config file for changes. - */ - -// Getters of logger_config -logger_config& logger_config::get_instance(void) -{ - static logger_config instance; - return instance; -} - -std::string logger_config::get_filename() -{ - logger_config& in = get_instance(); - return in.filename; -} - -unsigned int logger_config::get_watch_period() -{ - logger_config& in = get_instance(); - return in.watch_period; -} - -// Method to watch config file for changes -void logger_config::watch_file(std::string filename, unsigned int watch_period) -{ - auto last_write = std::filesystem::last_write_time(filename); - while (true) { - try { - auto current_time = std::filesystem::last_write_time(filename); - if (current_time > last_write) { - // std::cout<<"GNURadio Reloading logger - // configuration:"<<filename<<std::endl; - last_write = current_time; - // Should we wipe out all old configuration or just add the - // new? Just adding... logger_reset_config(); - logger_configured = logger_load_config(filename); - } - boost::this_thread::sleep( - boost::posix_time::time_duration(0, 0, watch_period, 0)); - } catch (const boost::thread_interrupted&) { - std::cerr << "GNURadio leaving logger config file watch." << std::endl; - break; - } +logging::logging() + : _default_level(spdlog::level::from_str( + prefs::singleton()->get_string("LOG", "log_level", "off"))), + _debug_level(spdlog::level::from_str( + prefs::singleton()->get_string("LOG", "debug_level", "off"))), + _default_backend(std::make_shared<spdlog::sinks::dist_sink_mt>()), + _debug_backend(std::make_shared<spdlog::sinks::dist_sink_mt>()) +{ + _default_backend->set_level(_default_level); + _debug_backend->set_level(_debug_level); + + + auto debug_console_sink = std::make_shared<spdlog::sinks::stderr_color_sink_st>(); + _debug_backend->add_sink(debug_console_sink); + + const auto pref = prefs::singleton(); + const auto default_file = pref->get_string("LOG", "log_file", ""); + + if (default_file == "stderr") { + auto console_sink = std::make_shared<spdlog::sinks::stderr_color_sink_st>(); + _default_backend->add_sink(console_sink); + } else if ((!default_file.empty()) && default_file != "stdout") { + auto file_sink = + std::make_shared<spdlog::sinks::basic_file_sink_st>(default_file, true); + _default_backend->add_sink(file_sink); } -} - -// Method to load the configuration. It only loads if the filename -// or watch has changed -void logger_config::load_config(std::string filename, unsigned int watch_period) -{ - logger_config& instance = get_instance(); - // Only reconfigure if filename or watch has changed - if (!logger_configured) { - instance.filename = filename; - instance.watch_period = watch_period; - // Stop any file watching thread - if (instance.watch_thread) - stop_watch(); - // Load configuration - // std::cout<<"GNURadio Loading logger - // configuration:"<<instance.filename<<std::endl; - logger_configured = logger_load_config(instance.filename); - // Start watch if required - if (instance.watch_period > 0) { - instance.watch_thread = std::make_unique<boost::thread>( - watch_file, instance.filename, instance.watch_period); - } - } -} - -// Method to stop the watcher thread -void logger_config::stop_watch() -{ - logger_config& instance = get_instance(); - if (instance.watch_thread) { - instance.watch_thread->interrupt(); - instance.watch_thread->join(); - instance.watch_thread.reset(); - } -} - -// Method to reset logger configuration -void logger_config::reset_config(void) -{ - logger_config& instance = get_instance(); - stop_watch(); - std::vector<log4cpp::Category*>* loggers = log4cpp::Category::getCurrentCategories(); - std::vector<log4cpp::Category*>::iterator logger = loggers->begin(); - // We can't destroy categories but we can neuter them by removing all appenders. - for (; logger != loggers->end(); logger++) { - (*logger)->removeAllAppenders(); - } - instance.filename = std::string(""); - instance.watch_period = 0; - logger_configured = false; -} - -/***************** Functions to call log4cpp methods *************************/ - -logger_ptr logger_get_logger(std::string name) -{ - if (log4cpp::Category::exists(name)) { - logger_ptr logger = &log4cpp::Category::getInstance(name); - return logger; - } else { - logger_ptr logger = &log4cpp::Category::getInstance(name); - logger->setPriority(log4cpp::Priority::NOTSET); - return logger; - } -} - -logger_ptr logger_get_configured_logger(const std::string& name) -{ - if (log4cpp::Category::exists(name)) - return &log4cpp::Category::getInstance(name); - - prefs* p = prefs::singleton(); - std::string config_file = p->get_string("LOG", "log_config", ""); - std::string log_level = p->get_string("LOG", "log_level", "off"); - std::string log_file = p->get_string("LOG", "log_file", ""); - GR_LOG_GETLOGGER(LOG, "gr_log." + name); - GR_LOG_SET_LEVEL(LOG, log_level); - - if (!log_file.empty()) { - if (log_file == "stdout") { - GR_LOG_SET_CONSOLE_APPENDER(LOG, "stdout", "gr::log :%p: %c{1} - %m%n"); - } else if (log_file == "stderr") { - GR_LOG_SET_CONSOLE_APPENDER(LOG, "stderr", "gr::log :%p: %c{1} - %m%n"); - } else { - GR_LOG_SET_FILE_APPENDER(LOG, log_file, true, "%r :%p: %c{1} - %m%n"); - } + if (default_file == "stdout") { + auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_st>(); + _default_backend->add_sink(console_sink); } - return LOG; } -bool logger_load_config(const std::string& config_filename) -{ - if (!config_filename.empty()) { - try { - log4cpp::PropertyConfigurator::configure(config_filename); - return true; - } catch (log4cpp::ConfigureFailure& e) { - std::cerr << "Logger config failed :" << e.what() << std::endl; - } - } - return false; -} -void logger_set_level(logger_ptr logger, const std::string& level) +logging& logging::singleton() { - std::string nocase = level; - std::transform(level.begin(), level.end(), nocase.begin(), ::tolower); - - if (nocase == "off" || nocase == "notset") - logger_set_level(logger, log4cpp::Priority::NOTSET); - else if (nocase == "all" || nocase == "debug") - logger_set_level(logger, log4cpp::Priority::DEBUG); - else if (nocase == "info") - logger_set_level(logger, log4cpp::Priority::INFO); - else if (nocase == "notice") - logger_set_level(logger, log4cpp::Priority::NOTICE); - else if (nocase == "warn") - logger_set_level(logger, log4cpp::Priority::WARN); - else if (nocase == "error") - logger_set_level(logger, log4cpp::Priority::ERROR); - else if (nocase == "crit") - logger_set_level(logger, log4cpp::Priority::CRIT); - else if (nocase == "alert") - logger_set_level(logger, log4cpp::Priority::ALERT); - else if (nocase == "fatal") - logger_set_level(logger, log4cpp::Priority::FATAL); - else if (nocase == "emerg") - logger_set_level(logger, log4cpp::Priority::EMERG); - else - throw std::runtime_error("logger_set_level: Bad level type."); + static logging the_only_one; + return the_only_one; } -void logger_set_level(logger_ptr logger, log4cpp::Priority::Value level) +spdlog::sink_ptr logging::default_backend() const { return _default_backend; } +void logging::add_default_sink(const spdlog::sink_ptr& sink) { - logger->setPriority(level); -} - -void logger_get_level(logger_ptr logger, std::string& level) + _default_backend->add_sink(sink); +}; +void logging::add_debug_sink(const spdlog::sink_ptr& sink) { - log4cpp::Priority::Value levelPtr = logger->getPriority(); - if (levelPtr == log4cpp::Priority::NOTSET) - level = "notset"; - if (levelPtr == log4cpp::Priority::DEBUG) - level = "debug"; - if (levelPtr == log4cpp::Priority::INFO) - level = "info"; - if (levelPtr == log4cpp::Priority::NOTICE) - level = "notice"; - if (levelPtr == log4cpp::Priority::WARN) - level = "warn"; - if (levelPtr == log4cpp::Priority::ERROR) - level = "error"; - if (levelPtr == log4cpp::Priority::CRIT) - level = "crit"; - if (levelPtr == log4cpp::Priority::ALERT) - level = "alert"; - if (levelPtr == log4cpp::Priority::FATAL) - level = "fatal"; - if (levelPtr == log4cpp::Priority::EMERG) - level = "emerg"; -} + _debug_backend->add_sink(sink); +}; -void logger_get_level(logger_ptr logger, log4cpp::Priority::Value level) +void logging::add_default_console_sink() { - level = logger->getPriority(); + add_default_sink(std::make_shared<spdlog::sinks::stdout_color_sink_st>()); } -void logger_add_console_appender(logger_ptr logger, - std::string target, - std::string pattern) +void logging::add_debug_console_sink() { - log4cpp::PatternLayout* layout = new log4cpp::PatternLayout(); - log4cpp::Appender* app; - if (target == "stdout") - app = new log4cpp::OstreamAppender("ConsoleAppender::", &std::cout); - else - app = new log4cpp::OstreamAppender("ConsoleAppender::", &std::cerr); - - layout->setConversionPattern(pattern); - app->setLayout(layout); - logger->setAppender(app); + add_debug_sink(std::make_shared<spdlog::sinks::stdout_color_sink_st>()); } -void logger_set_console_appender(logger_ptr logger, - std::string target, - std::string pattern) +logger::logger(const std::string& logger_name) + : _name(logger_name), + d_logger( + std::make_shared<spdlog::logger>(_name, logging::singleton().default_backend())) { - logger->removeAllAppenders(); - logger_add_console_appender(logger, target, pattern); + d_logger->set_level(logging::singleton().default_level()); + // gr::log :%p: %c{1} - %m%n + // :level: block alias - message + d_logger->set_pattern(logging::default_pattern); } -void logger_add_file_appender(logger_ptr logger, - std::string filename, - bool append, - std::string pattern) -{ - log4cpp::PatternLayout* layout = new log4cpp::PatternLayout(); - log4cpp::Appender* app = - new log4cpp::FileAppender("FileAppender::" + filename, filename, append); - layout->setConversionPattern(pattern); - app->setLayout(layout); - logger->setAppender(app); -} +log_level logger::get_level() const { return d_logger->level(); } -void logger_set_file_appender(logger_ptr logger, - std::string filename, - bool append, - std::string pattern) +const std::string logger::get_string_level() const { - logger->removeAllAppenders(); - logger_add_file_appender(logger, filename, append, pattern); + const auto view = spdlog::level::to_string_view(d_logger->level()); + return std::string(view.begin(), view.end()); } -void logger_add_rollingfile_appender(logger_ptr logger, - std::string filename, - size_t filesize, - int bkup_index, - bool append, - mode_t mode, - std::string pattern) -{ - log4cpp::PatternLayout* layout = new log4cpp::PatternLayout(); - log4cpp::Appender* app = new log4cpp::RollingFileAppender( - "RollFileAppender::" + filename, filename, filesize, bkup_index, append, mode); - layout->setConversionPattern(pattern); - app->setLayout(layout); - logger->setAppender(app); -} +void logger::get_level(std::string& level) const { level = get_string_level(); } +void logger::set_level(const log_level level) { d_logger->set_level(level); } -std::vector<std::string> logger_get_logger_names(void) +void logger::set_level(const std::string& level) { - std::vector<std::string> names; - std::vector<log4cpp::Category*>* loggers = log4cpp::Category::getCurrentCategories(); - std::vector<log4cpp::Category*>::iterator logger = loggers->begin(); - - for (; logger != loggers->end(); logger++) { - names.push_back((*logger)->getName()); + auto parsed_level = spdlog::level::from_str(level); + if (parsed_level == spdlog::level::off) { + if (level == "notice") { + parsed_level = spdlog::level::info; + } else if (level == "warn") { + // older versions of spdlog don't convert this themselves + parsed_level = spdlog::level::warn; + } else if (level == "crit" || level == "alert" || level == "fatal" || + level == "emerg") { + parsed_level = spdlog::level::critical; + } } - return names; + d_logger->set_level(parsed_level); } -} /* namespace gr */ - -/****** Start Methods to provide Python the capabilities of the macros ********/ -void gr_logger_config(const std::string config_filename, unsigned int watch_period) +const std::string& logger::name() const { return _name; } +void logger::set_name(const std::string& name) { - GR_CONFIG_AND_WATCH_LOGGER(config_filename, watch_period); + _name = name; + d_logger->set_pattern(logging::default_pattern); } -std::vector<std::string> gr_logger_get_logger_names(void) -{ - std::vector<std::string> names; - GR_GET_LOGGER_NAMES(names); - return names; -} - -void gr_logger_reset_config(void) { GR_RESET_CONFIGURATION(); } - -// Remaining capability provided by gr::logger class in gnuradio/logger.h - -namespace gr { - bool configure_default_loggers(gr::logger_ptr& l, gr::logger_ptr& d, - const std::string name) + const std::string& name) { - prefs* p = prefs::singleton(); - std::string config_file = p->get_string("LOG", "log_config", ""); - std::string log_level = p->get_string("LOG", "log_level", "off"); - std::string log_file = p->get_string("LOG", "log_file", ""); - std::string debug_level = p->get_string("LOG", "debug_level", "off"); - std::string debug_file = p->get_string("LOG", "debug_file", ""); - - GR_CONFIG_LOGGER(config_file); - - GR_LOG_GETLOGGER(LOG, "gr_log." + name); - GR_LOG_SET_LEVEL(LOG, log_level); - - if (!log_file.empty()) { - if (log_file == "stdout") { - GR_LOG_SET_CONSOLE_APPENDER(LOG, "stdout", "gr::log :%p: %c{1} - %m%n"); - } else if (log_file == "stderr") { - GR_LOG_SET_CONSOLE_APPENDER(LOG, "stderr", "gr::log :%p: %c{1} - %m%n"); - } else { - GR_LOG_SET_FILE_APPENDER(LOG, log_file, true, "%r :%p: %c{1} - %m%n"); - } + if (l == nullptr) { + l = std::make_shared<gr::logger_ptr::element_type>(name); } - l = LOG; - - GR_LOG_GETLOGGER(DLOG, "gr_log_debug." + name); - GR_LOG_SET_LEVEL(DLOG, debug_level); - if (!debug_file.empty()) { - if (debug_file == "stdout") { - GR_LOG_SET_CONSOLE_APPENDER(DLOG, "stdout", "gr::debug :%p: %c{1} - %m%n"); - } else if (debug_file == "stderr") { - GR_LOG_SET_CONSOLE_APPENDER(DLOG, "stderr", "gr::debug :%p: %c{1} - %m%n"); - } else { - GR_LOG_SET_FILE_APPENDER(DLOG, debug_file, true, "%r :%p: %c{1} - %m%n"); - } - } - d = DLOG; - return true; -} - -bool update_logger_alias(const std::string& name, const std::string& alias) -{ - prefs* p = prefs::singleton(); - std::string log_file = p->get_string("LOG", "log_file", ""); - std::string debug_file = p->get_string("LOG", "debug_file", ""); - - GR_LOG_GETLOGGER(LOG, "gr_log." + name); - if (!log_file.empty()) { - if (log_file == "stdout") { - boost::format str("gr::log :%%p: %1% - %%m%%n"); - GR_LOG_SET_CONSOLE_APPENDER(LOG, "stdout", boost::str(str % alias)); - } else if (log_file == "stderr") { - boost::format str("gr::log :%%p: %1% - %%m%%n"); - GR_LOG_SET_CONSOLE_APPENDER(LOG, "stderr", boost::str(str % alias)); - } else { - boost::format str("%%r :%%p: %1% - %%m%%n"); - GR_LOG_SET_FILE_APPENDER(LOG, log_file, true, boost::str(str % alias)); - } + if (d == nullptr) { + d = std::make_shared<gr::logger_ptr::element_type>(name); } + l->set_level(logging::singleton().default_level()); + d->set_level(logging::singleton().debug_level()); + l->set_name(name); + d->set_name(name); return true; } |