diff options
Diffstat (limited to 'host/lib/utils')
| -rw-r--r-- | host/lib/utils/log.cpp | 325 | 
1 files changed, 182 insertions, 143 deletions
| diff --git a/host/lib/utils/log.cpp b/host/lib/utils/log.cpp index 42219e925..1d87a0b3d 100644 --- a/host/lib/utils/log.cpp +++ b/host/lib/utils/log.cpp @@ -18,17 +18,17 @@  #include <uhd/utils/log.hpp>  #include <uhd/utils/static.hpp>  #include <uhd/utils/paths.hpp> -#include <boost/filesystem.hpp> -#include <boost/thread/mutex.hpp> +#include <uhd/utils/tasks.hpp> +#include <uhd/transport/bounded_buffer.hpp>  #include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/make_shared.hpp>  #include <boost/thread/locks.hpp> -#include <boost/interprocess/sync/file_lock.hpp> +#include <boost/thread/mutex.hpp>  #include <fstream>  #include <cctype> +#include <atomic> -namespace fs = boost::filesystem;  namespace pt = boost::posix_time; -namespace ip = boost::interprocess;  static const std::string PURPLE = "\033[35;1m"; // purple  static const std::string BLUE = "\033[34;1m"; // blue @@ -38,7 +38,9 @@ static const std::string RED = "\033[31;0m"; // red  static const std::string BRED = "\033[31;1m"; // bright red  static const std::string RESET_COLORS = "\033[39;0m"; // reset colors - +/*********************************************************************** + * Helpers + **********************************************************************/  static const std::string verbosity_color(const uhd::log::severity_level &level){      switch(level){      case (uhd::log::trace): @@ -58,86 +60,178 @@ static const std::string verbosity_color(const uhd::log::severity_level &level){      }  } +//! get the relative file path from the host directory +inline std::string path_to_filename(std::string path) +{ +    return path.substr(path.find_last_of("/\\") + 1); +}  /*********************************************************************** - * Global resources for the logger + * Logger backends   **********************************************************************/ -class log_resource_type{ + + +void console_log( +    const uhd::log::logging_info &log_info +) { +        std::clog +#ifdef UHD_LOG_CONSOLE_COLOR +            << verbosity_color(log_info.verbosity) +#endif +#ifdef UHD_LOG_CONSOLE_TIME +            << "[" << pt::to_simple_string(log_info.time) << "] " +#endif +#ifdef UHD_LOG_CONSOLE_THREAD +            << "[0x" << log_info.thread_id << "] " +#endif +#ifdef UHD_LOG_CONSOLE_SRC +            << "[" << path_to_filename(log_info.file) << ":" << log_info.line << "] " +#endif +            << "[" << log_info.verbosity << "] " +            << "[" << log_info.component << "] " +#ifdef UHD_LOG_CONSOLE_COLOR +            << RESET_COLORS +#endif +            << log_info.message +            << std::endl +            ; +} + +class file_logger_backend +{  public: -    uhd::log::severity_level level; -    uhd::log::severity_level file_level; -    uhd::log::severity_level console_level; +    file_logger_backend(const std::string &file_path) +    { +        _file_stream.exceptions(std::ofstream::failbit | std::ofstream::badbit); +        if (!file_path.empty()){ +            try { +                _file_stream.open(file_path.c_str(), std::fstream::out | std::fstream::app); +            } catch (const std::ofstream::failure& fail){ +                std::cerr << "Error opening log file: " << fail.what() << std::endl; +            } +        } + +    } -    log_resource_type(void): level(uhd::log::info), file_level(uhd::log::info), console_level(uhd::log::info){ +    void log(const uhd::log::logging_info &log_info) +    { +        if (_file_stream.is_open()){ +            _file_stream +                << pt::to_simple_string(log_info.time) << "," +                << "0x" << log_info.thread_id << "," +                << path_to_filename(log_info.file) << ":" << log_info.line << "," +                << log_info.verbosity << "," +                << log_info.component << "," +                << log_info.message +                << std::endl; +            ; +        } +    } -        //file lock pointer must be null -        _file_lock = NULL; -        //default to no file logging -        this->file_logging = false; +    ~file_logger_backend() +    { +        if (_file_stream.is_open()){ +            _file_stream.close(); +        } +    } -        //set the default log level -        this->level = uhd::log::off; -        this->file_level = uhd::log::off; -        this->console_level = uhd::log::off; +private: +    std::ofstream _file_stream; +}; + +/*********************************************************************** + * Global resources for the logger + **********************************************************************/ + +#define UHD_CONSOLE_LOGGER_KEY "console" +#define UHD_FILE_LOGGER_KEY "file" + +class log_resource { +public: +    uhd::log::severity_level global_level; +    std::map<std::string, uhd::log::severity_level> logger_level; + +    log_resource(void): +        global_level(uhd::log::off), +        _exit(false), +        _log_queue(10) +    {          //allow override from macro definition  #ifdef UHD_LOG_MIN_LEVEL -        this->level = _get_log_level(BOOST_STRINGIZE(UHD_LOG_MIN_LEVEL), this->level); -#endif -#if defined(UHD_LOG_FILE_LEVEL) && defined(UHD_LOG_FILE_PATH) -        this->file_level = _get_log_level(BOOST_STRINGIZE(UHD_LOG_FILE_LEVEL), this->file_level); -#endif -#ifdef UHD_LOG_CONSOLE_LEVEL -        this->console_level = _get_log_level(BOOST_STRINGIZE(UHD_LOG_CONSOLE_LEVEL), this->console_level); +        this->global_level = _get_log_level(BOOST_STRINGIZE(UHD_LOG_MIN_LEVEL), this->global_level);  #endif -#ifdef UHD_LOG_FILE -        this->log_file_target = BOOST_STRINGIZE(UHD_LOG_FILE); -        this->file_logging = true; -#endif - -        //allow override from environment variables +       //allow override from environment variables          const char * log_level_env = std::getenv("UHD_LOG_LEVEL"); -        if (log_level_env != NULL && log_level_env[0] != '\0') this->level = _get_log_level(log_level_env, this->level); +        if (log_level_env != NULL && log_level_env[0] != '\0') this->global_level = _get_log_level(log_level_env, this->global_level); -        const char * log_file_level_env = std::getenv("UHD_LOG_FILE_LEVEL"); -        if (log_file_level_env != NULL && log_file_level_env[0] != '\0') this->file_level = _get_log_level(log_file_level_env, this->file_level); +// console logging support +#ifndef UHD_LOG_CONSOLE_DISABLE +        uhd::log::severity_level console_level = uhd::log::trace; +#ifdef UHD_LOG_CONSOLE_LEVEL +        console_level = _get_log_level(BOOST_STRINGIZE(UHD_LOG_CONSOLE_LEVEL), console_level); +#endif          const char * log_console_level_env = std::getenv("UHD_LOG_CONSOLE_LEVEL"); -        if (log_console_level_env != NULL && log_console_level_env[0] != '\0') this->console_level = _get_log_level(log_console_level_env, this->console_level); +        if (log_console_level_env != NULL && log_console_level_env[0] != '\0') console_level = _get_log_level(log_console_level_env, console_level); +        logger_level[UHD_CONSOLE_LOGGER_KEY] = console_level; +        _loggers[UHD_CONSOLE_LOGGER_KEY] = &console_log; +#endif +        uhd::log::severity_level file_level = uhd::log::trace; +        std::string log_file_target; +#if defined(UHD_LOG_FILE_LEVEL) && defined(UHD_LOG_FILE_PATH) +        file_level = _get_log_level(BOOST_STRINGIZE(UHD_LOG_FILE_LEVEL), file_level); +        log_file_target = BOOST_STRINGIZE(UHD_LOG_FILE); +#endif +        const char * log_file_level_env = std::getenv("UHD_LOG_FILE_LEVEL"); +        if (log_file_level_env != NULL && log_file_level_env[0] != '\0'){ +            file_level = _get_log_level(log_file_level_env, file_level); +        }          const char* log_file_env = std::getenv("UHD_LOG_FILE");          if ((log_file_env != NULL) && (log_file_env[0] != '\0')) { -            this->log_file_target = log_file_env; -            this->file_logging = true; +            log_file_target = std::string(log_file_env);          } +        if (!log_file_target.empty()){ +            logger_level[UHD_FILE_LOGGER_KEY] = file_level; +            auto F = boost::make_shared<file_logger_backend>(log_file_target); +            _loggers[UHD_FILE_LOGGER_KEY] = [F](const uhd::log::logging_info& log_info){F->log(log_info);}; +        } +        _pop_task = uhd::task::make([this](){this->pop_task();}); +      } -    ~log_resource_type(void){ -        if (this->file_logging){ -            boost::lock_guard<boost::mutex> lock(_mutex); -            _file_stream.close(); -            if (_file_lock != NULL) delete _file_lock; -        } +    ~log_resource(void){ +        _exit = true; +        _pop_task.reset();      } -    void log_to_file(const std::string &log_msg){ -        if ( this->file_logging ){ -            boost::lock_guard<boost::mutex> lock(_mutex); -            if (_file_lock == NULL){ -                _file_stream.open(this->log_file_target.c_str(), std::fstream::out | std::fstream::app); -                _file_lock = new ip::file_lock(this->log_file_target.c_str()); +    void push(const uhd::log::logging_info& log_info) +    { + +        _log_queue.push_with_haste(log_info); +    } + +    void pop_task() +    { +        while (!_exit) { +            uhd::log::logging_info log_info; +            if (_log_queue.pop_with_timed_wait(log_info, 1)){ +                for (const auto &logger : _loggers) { +                    auto level = logger_level.find(logger.first); +                    if(level != logger_level.end() && log_info.verbosity < level->second){ +                        UHD_VAR(level->second) +                            continue; +                    } +                    logger.second(log_info); +                }              } -            _file_lock->lock(); -            _file_stream << log_msg << std::flush; -            _file_lock->unlock();          }      }  private: -    //! set the log level from a string that is either a digit or an enum name -    bool file_logging; -    std::string log_file_target; +    uhd::task::sptr _pop_task;      uhd::log::severity_level _get_log_level(const std::string &log_level_str,                                              const uhd::log::severity_level &previous_level){          if (std::isdigit(log_level_str[0])) { @@ -147,6 +241,7 @@ private:                  log_level_num <= uhd::log::fatal) {                  return log_level_num;              }else{ +                UHD_LOGGER_ERROR("LOG") << "Failed to set log level to: " << log_level_str;                  return previous_level;              }          } @@ -163,118 +258,62 @@ private:          return previous_level;      } -    //file stream and lock: -    std::ofstream _file_stream; -    ip::file_lock *_file_lock; -    boost::mutex _mutex; +    std::atomic<bool> _exit; +    std::map<std::string, uhd::log::log_fn_t> _loggers; +    uhd::transport::bounded_buffer<uhd::log::logging_info> _log_queue; // Init auf size 10 oder so  }; -UHD_SINGLETON_FCN(log_resource_type, log_rs); +UHD_SINGLETON_FCN(log_resource, log_rs);  /***********************************************************************   * The logger object implementation   **********************************************************************/ -//! get the relative file path from the host directory - -inline std::string path_to_filename(std::string path) -{ -    return path.substr(path.find_last_of("/\\") + 1); -} -  uhd::_log::log::log(      const uhd::log::severity_level verbosity,      const std::string &file,      const unsigned int line,      const std::string &component, -    const boost::thread::id id -    ) +    const boost::thread::id thread_id +    ) : +    _log_it(verbosity >= log_rs().global_level)  { -    _log_it = (verbosity >= log_rs().level); -    _log_file =(verbosity >= log_rs().file_level); -    _log_console = (verbosity >= log_rs().console_level); -    if (_log_it) -    { -        if (_log_file){ -        const std::string time = pt::to_simple_string(pt::microsec_clock::local_time()); -        _file -            << time << "," -            << "0x" << id << "," -            << path_to_filename(file) << ":" << line << "," -            << verbosity << "," -            << component << "," -        ; +    if (_log_it){ +        this->_log_info = uhd::log::logging_info( +            pt::microsec_clock::local_time(), +            verbosity, +            file, +            line, +            component, +            thread_id);          } -#ifndef UHD_LOG_CONSOLE_DISABLE -        if (_log_console){ -#ifdef UHD_LOG_CONSOLE_TIME -            const std::string time = pt::to_simple_string(pt::microsec_clock::local_time()); -#endif -            _console -#ifdef UHD_LOG_CONSOLE_COLOR -                << verbosity_color(verbosity) -#endif -#ifdef UHD_LOG_CONSOLE_TIME -                << "[" << time << "] " -#endif -#ifdef UHD_LOG_CONSOLE_THREAD -                << "[0x" << id << "] " -#endif -#ifdef UHD_LOG_CONSOLE_SRC -                << "[" << path_to_filename(file) << ":" << line << "] " -#endif -                << "[" << verbosity << "] " -                << "[" << component << "] " -#ifdef UHD_LOG_CONSOLE_COLOR -                << RESET_COLORS -#endif -                ; -        } -#endif -    }  }  uhd::_log::log::~log(void)  { -    if (not _log_it) -        return; -#ifndef UHD_LOG_CONSOLE_DISABLE -    if ( _log_console ){ -        std::clog << _console.str() << _ss.str() << std::endl; -        } -#endif -    if ( _log_file){ -        _file << _ss.str() << std::endl; -        try{ -            log_rs().log_to_file(_file.str()); -        } -        catch(const std::exception &e){ -            /*! -             * Critical behavior below. -             * The following steps must happen in order to avoid a lock-up condition. -             * This is because the message facility will call into the logging facility. -             * Therefore we must disable the logger (level = never) before messaging. -             */ -            log_rs().level = uhd::log::off; -            std::cerr -                << "Logging failed: " << e.what() << std::endl -                << "Logging has been disabled for this process" << std::endl -                ; -        } +    if (_log_it) { +        this->_log_info.message = _ss.str(); +        log_rs().push(this->_log_info);      }  }  void -uhd::_log::log::set_log_level(uhd::log::severity_level level){ -    log_rs().level = level; +uhd::log::set_log_level(uhd::log::severity_level level){ +    log_rs().global_level = level; +} + +void +uhd::log::set_logger_level(const std::string &key, uhd::log::severity_level level){ +    log_rs().logger_level[key] = level;  }  void -uhd::_log::log::set_console_level(uhd::log::severity_level level){ -    log_rs().console_level = level; +uhd::log::set_console_level(uhd::log::severity_level level){ +    set_logger_level(UHD_CONSOLE_LOGGER_KEY, level);  }  void -uhd::_log::log::set_file_level(uhd::log::severity_level level){ -    log_rs().file_level = level; +uhd::log::set_file_level(uhd::log::severity_level level){ +    set_logger_level(UHD_FILE_LOGGER_KEY, level);  } + | 
