// // Copyright 2012,2014,2016 Ettus Research LLC // // This program 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 of the License, or // (at your option) any later version. // // This program 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 this program. If not, see . // #include #include #include #include #include #include #include #include #include #include #include #include namespace pt = boost::posix_time; static const std::string PURPLE = "\033[35;1m"; // purple static const std::string BLUE = "\033[34;1m"; // blue static const std::string GREEN = "\033[32;1m"; // green static const std::string YELLOW = "\033[33;1m"; // yellow 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): return PURPLE; case(uhd::log::debug): return BLUE; case(uhd::log::info): return GREEN; case(uhd::log::warning): return YELLOW; case(uhd::log::error): return RED; case(uhd::log::fatal): return BRED; default: return RESET_COLORS; } } //! 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); } /*********************************************************************** * Logger backends **********************************************************************/ 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: 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; } } } 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_logger_backend() { if (_file_stream.is_open()){ _file_stream.close(); } } 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 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->global_level = _get_log_level(BOOST_STRINGIZE(UHD_LOG_MIN_LEVEL), this->global_level); #endif //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->global_level = _get_log_level(log_level_env, this->global_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') 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')) { 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(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(void){ _exit = true; _pop_task.reset(); } 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){ continue; } logger.second(log_info); } } } // Exit procedure: Clear the queue uhd::log::logging_info log_info; while (_log_queue.pop_with_haste(log_info)) { for (const auto &logger : _loggers) { auto level = logger_level.find(logger.first); if (level != logger_level.end() && log_info.verbosity < level->second){ continue; } logger.second(log_info); } } } void add_logger(const std::string &key, uhd::log::log_fn_t logger_fn) { _loggers[key] = logger_fn; } private: 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])) { const uhd::log::severity_level log_level_num = uhd::log::severity_level(std::stoi(log_level_str)); if (log_level_num >= uhd::log::trace and 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; } } #define if_loglevel_equal(name) \ else if (log_level_str == #name) return uhd::log::name if_loglevel_equal(trace); if_loglevel_equal(debug); if_loglevel_equal(info); if_loglevel_equal(warning); if_loglevel_equal(error); if_loglevel_equal(fatal); if_loglevel_equal(off); return previous_level; } std::atomic _exit; std::map _loggers; uhd::transport::bounded_buffer _log_queue; // Init auf size 10 oder so }; UHD_SINGLETON_FCN(log_resource, log_rs); /*********************************************************************** * The logger object implementation **********************************************************************/ 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 thread_id ) : _log_it(verbosity >= log_rs().global_level) { if (_log_it){ this->_log_info = uhd::log::logging_info( pt::microsec_clock::local_time(), verbosity, file, line, component, thread_id); } } uhd::_log::log::~log(void) { if (_log_it) { this->_log_info.message = _ss.str(); log_rs().push(this->_log_info); } } void uhd::log::add_logger(const std::string &key, log_fn_t logger_fn) { log_rs().add_logger(key, logger_fn); } void 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::set_console_level(uhd::log::severity_level level){ set_logger_level(UHD_CONSOLE_LOGGER_KEY, level); } void uhd::log::set_file_level(uhd::log::severity_level level){ set_logger_level(UHD_FILE_LOGGER_KEY, level); }