/* -*- 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 */