diff options
Diffstat (limited to 'gnuradio-runtime/lib/gr_logger.cc')
-rw-r--r-- | gnuradio-runtime/lib/gr_logger.cc | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/gnuradio-runtime/lib/gr_logger.cc b/gnuradio-runtime/lib/gr_logger.cc new file mode 100644 index 0000000000..82737128bb --- /dev/null +++ b/gnuradio-runtime/lib/gr_logger.cc @@ -0,0 +1,295 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/******************************************************************************* +* Author: Mark Plett +* Description: +* The gr_log module wraps the log4cpp library for logging in gnuradio. +*******************************************************************************/ + +#ifndef ENABLE_GR_LOG +#include "config.h" +#endif + +#include <gr_logger.h> +#include <stdexcept> +#include <algorithm> + +#ifdef ENABLE_GR_LOG +#ifdef HAVE_LOG4CPP + +/**************************** 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 teh 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){ + std::time_t last_write(boost::filesystem::last_write_time(filename)); + std::time_t current_time(0); + while(true){ + try{ + current_time = boost::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_load_config(filename); + }; + boost::this_thread::sleep(boost::posix_time::time_duration(0,0,watch_period,0)); + } + catch(const boost::thread_interrupted&){ + std::cout<<"GNURadio leaving logger config file watch."<<std::endl; + break; + }; + }; +}; + +// Method to load the confifuration. 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(instance.filename!=filename || watch_period!=instance.watch_period){ + instance.filename = filename; + instance.watch_period = watch_period; +// Stop any file watching thread + if(instance.watch_thread!=NULL) stop_watch(); +// Load configuration + std::cout<<"GNURadio Loading logger configuration:"<<instance.filename<<std::endl; + logger_load_config(instance.filename); +// Start watch if required + if(instance.watch_period>0){ + instance.watch_thread = new 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(); + delete(instance.watch_thread); + instance.watch_thread=NULL; + }; +}; + +// 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; +} + +/***************** Functions to call log4cpp methods *************************/ + +gr_logger_ptr +logger_get_logger(std::string name) +{ + if(log4cpp::Category::exists(name)){ + gr_logger_ptr logger = &log4cpp::Category::getInstance(name); + return logger; + } + else + { + gr_logger_ptr logger = &log4cpp::Category::getInstance(name); + logger->setPriority(log4cpp::Priority::NOTSET); + return logger; + }; +}; + +void +logger_load_config(const std::string &config_filename) +{ + if(config_filename.size() != 0) { + try + { + log4cpp::PropertyConfigurator::configure(config_filename); + } + catch( log4cpp::ConfigureFailure &e ) + { + std::cout << "Logger config failed :" << e.what() << std::endl; + } + }; +} + +void +logger_set_level(gr_logger_ptr logger, const std::string &level) +{ + 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.\n"); +} + +void +logger_set_level(gr_logger_ptr logger, log4cpp::Priority::Value level) +{ + logger->setPriority(level); +} + +void +logger_get_level(gr_logger_ptr logger, std::string &level) +{ + log4cpp::Priority::Value levelPtr = logger->getPriority(); + if(levelPtr == log4cpp::Priority::NOTSET) level = "noset"; + 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"; +}; + +void +logger_get_level(gr_logger_ptr logger,log4cpp::Priority::Value level) +{ + level = logger->getPriority(); +} + +void +logger_add_console_appender(gr_logger_ptr logger,std::string target,std::string pattern) +{ + + 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); + +} + +void +logger_add_file_appender(gr_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); + layout->setConversionPattern(pattern); + app->setLayout(layout); + logger->setAppender(app); + +} + +void +logger_add_rollingfile_appender(gr_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); +} + +std::vector<std::string> +logger_get_logger_names(void){ + 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()); + }; + return names; + +} + +#endif /* HAVE_LOG4CPP */ + +/****** Start Methods to provide Python the capabilities of the macros ********/ +void gr_logger_config(const std::string config_filename, unsigned int watch_period){ + GR_CONFIG_AND_WATCH_LOGGER(config_filename,watch_period); +}; +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 gr_logger.h + +#endif /* ENABLE_GR_LOGGER */ |