1 // 2 // Copyright 2011 Ettus Research LLC 3 // Copyright 2018 Ettus Research, a National Instruments Company 4 // 5 // SPDX-License-Identifier: GPL-3.0-or-later 6 // 7 8 #pragma once 9 10 #include <uhd/config.hpp> 11 #include <boost/current_function.hpp> 12 #include <boost/thread/thread.hpp> 13 #include <iomanip> 14 #include <iostream> 15 #include <ostream> 16 #include <sstream> 17 #include <string> 18 19 /*! \file log.hpp 20 * 21 * \section loghpp_logging The UHD logging facility 22 * 23 * The logger enables UHD library code to easily log events into a file and 24 * display messages above a certain level in the terminal. 25 * Log entries are time-stamped and stored with file, line, and function. 26 * Each call to the UHD_LOG macros is thread-safe. Each thread will aquire the 27 * lock for the logger. 28 * 29 * Note: More information on the logging subsystem can be found on 30 * \ref page_logging. 31 * 32 * To disable console logging completely at compile time specify 33 * `-DUHD_LOG_CONSOLE_DISABLE` during configuration with CMake. 34 * 35 * By default no file logging will occur. Set a log file path: 36 * - at compile time by specifying `-DUHD_LOG_FILE=$file_path` 37 * - and/or override at runtime by setting the environment variable 38 * `UHD_LOG_FILE` 39 * 40 * \subsection loghpp_levels Log levels 41 * 42 * See also \ref logging_levels. 43 * 44 * All log messages with verbosity greater than or equal to the log level 45 * (in other words, as often or less often than the current log level) 46 * are recorded to std::clog and/or the log file. 47 * Log levels can be specified using string or numeric values of 48 * uhd::log::severity_level. 49 * 50 * The default log level is "info", but can be overridden: 51 * - at compile time by setting the pre-processor define `-DUHD_LOG_MIN_LEVEL`. 52 * - at runtime by setting the environment variable `UHD_LOG_LEVEL`. 53 * - for console logging by setting `(-D)UHD_LOG_CONSOLE_LEVEL` at 54 * run-/compiletime 55 * - for file logging by setting `(-D)UHD_LOG_FILE_LEVEL` at run-/compiletime 56 * 57 * UHD_LOG_LEVEL can be the name of a verbosity enum or integer value: 58 * - Example pre-processor define: `-DUHD_LOG_MIN_LEVEL=3` 59 * - Example pre-processor define: `-DUHD_LOG_MIN_LEVEL=info` 60 * - Example environment variable: `export UHD_LOG_LEVEL=3` 61 * - Example environment variable: `export UHD_LOG_LEVEL=info` 62 * 63 * \subsection loghpp_formatting Log formatting 64 * 65 * The log format for messages going into a log file is CSV. 66 * All log messages going into a logfile will contain following fields: 67 * - timestamp 68 * - thread-id 69 * - source-file + line information 70 * - severity level 71 * - component/channel information which logged the information 72 * - the actual log message 73 * 74 * The log format of log messages displayed on the terminal is plain text with 75 * space separated tags prepended. 76 * For example: 77 * - `[INFO] [X300] This is a informational log message` 78 * 79 * The log format for log output on the console by using these preprocessor 80 * defines in CMake: 81 * - `-DUHD_LOG_CONSOLE_TIME` adds a timestamp [2017-01-01 00:00:00.000000] 82 * - `-DUHD_LOG_CONSOLE_THREAD` adds a thread-id `[0x001234]` 83 * - `-DUHD_LOG_CONSOLE_SRC` adds a sourcefile and line tag `[src_file:line]` 84 */ 85 86 /* 87 * Advanced logging macros 88 * UHD_LOG_MIN_LEVEL definitions 89 * trace: 0 90 * debug: 1 91 * info: 2 92 * warning: 3 93 * error: 4 94 * fatal: 5 95 */ 96 97 namespace uhd { namespace log { 98 /*! Logging severity levels 99 * 100 * Either numeric value or string can be used to define loglevel in 101 * CMake and environment variables 102 */ 103 enum severity_level { 104 trace = 0, /**< displays every available log message */ 105 debug = 1, /**< displays most log messages necessary for debugging internals */ 106 info = 2, /**< informational messages about setup and what is going on*/ 107 warning = 3, /**< something is not right but operation can continue */ 108 error = 4, /**< something has gone wrong */ 109 fatal = 5, /**< something has gone horribly wrong */ 110 off = 6, /**< logging is turned off */ 111 }; 112 113 /*! Logging info structure 114 * 115 * Information needed to create a log entry is fully contained in the 116 * logging_info structure. 117 */ 118 struct UHD_API logging_info 119 { logging_infouhd::log::logging_info120 logging_info() : verbosity(uhd::log::off) {} logging_infouhd::log::logging_info121 logging_info(const boost::posix_time::ptime& time_, 122 const uhd::log::severity_level& verbosity_, 123 const std::string& file_, 124 const unsigned int& line_, 125 const std::string& component_, 126 const boost::thread::id& thread_id_) 127 : time(time_) 128 , verbosity(verbosity_) 129 , file(file_) 130 , line(line_) 131 , component(component_) 132 , thread_id(thread_id_) 133 { /* nop */ 134 } 135 136 boost::posix_time::ptime time; 137 uhd::log::severity_level verbosity; 138 std::string file; 139 unsigned int line; 140 std::string component; 141 boost::thread::id thread_id; 142 std::string message; 143 }; 144 145 /*! Set the global log level 146 * 147 * The global log level gets applied before the specific log level. 148 * So, if the global log level is 'info', no logger can can print 149 * messages at level 'debug' or below. 150 */ 151 UHD_API void set_log_level(uhd::log::severity_level level); 152 153 /*! Set the log level for the console logger (if defined). 154 * 155 * Short-hand for `set_logger_level("console", level);` 156 */ 157 UHD_API void set_console_level(uhd::log::severity_level level); 158 159 /*! Set the log level for the file logger (if defined) 160 * 161 * Short-hand for `set_logger_level("file", level);` 162 */ 163 UHD_API void set_file_level(uhd::log::severity_level level); 164 165 /*! Set the log level for any specific logger. 166 * 167 * \param logger Name of the logger 168 * \param level New log level for this logger. 169 * 170 * \throws uhd::key_error if \p logger was not defined 171 */ 172 UHD_API void set_logger_level(const std::string& logger, uhd::log::severity_level level); 173 }} // namespace uhd::log 174 175 //! \cond 176 //! Internal logging macro to be used in other macros 177 #define _UHD_LOG_INTERNAL(component, level) \ 178 uhd::_log::log(level, __FILE__, __LINE__, component, boost::this_thread::get_id()) 179 //! \endcond 180 181 // macro-style logging (compile-time determined) 182 #if UHD_LOG_MIN_LEVEL < 1 183 # define UHD_LOG_TRACE(component, message) \ 184 _UHD_LOG_INTERNAL(component, uhd::log::trace) << message; 185 #else 186 # define UHD_LOG_TRACE(component, message) 187 #endif 188 189 #if UHD_LOG_MIN_LEVEL < 2 190 # define UHD_LOG_DEBUG(component, message) \ 191 _UHD_LOG_INTERNAL(component, uhd::log::debug) << message; 192 #else 193 # define UHD_LOG_DEBUG(component, message) 194 #endif 195 196 #if UHD_LOG_MIN_LEVEL < 3 197 # define UHD_LOG_INFO(component, message) \ 198 _UHD_LOG_INTERNAL(component, uhd::log::info) << message; 199 #else 200 # define UHD_LOG_INFO(component, message) 201 #endif 202 203 #if UHD_LOG_MIN_LEVEL < 4 204 # define UHD_LOG_WARNING(component, message) \ 205 _UHD_LOG_INTERNAL(component, uhd::log::warning) << message; 206 #else 207 # define UHD_LOG_WARNING(component, message) 208 #endif 209 210 #if UHD_LOG_MIN_LEVEL < 5 211 # define UHD_LOG_ERROR(component, message) \ 212 _UHD_LOG_INTERNAL(component, uhd::log::error) << message; 213 #else 214 # define UHD_LOG_ERROR(component, message) 215 #endif 216 217 #if UHD_LOG_MIN_LEVEL < 6 218 # define UHD_LOG_FATAL(component, message) \ 219 _UHD_LOG_INTERNAL(component, uhd::log::fatal) << message; 220 #else 221 # define UHD_LOG_FATAL(component, message) 222 #endif 223 224 #define RFNOC_LOG_TRACE(message) UHD_LOG_TRACE(this->get_unique_id(), message) 225 #define RFNOC_LOG_DEBUG(message) UHD_LOG_DEBUG(this->get_unique_id(), message) 226 #define RFNOC_LOG_INFO(message) UHD_LOG_INFO(this->get_unique_id(), message) 227 #define RFNOC_LOG_WARNING(message) UHD_LOG_WARNING(this->get_unique_id(), message) 228 #define RFNOC_LOG_ERROR(message) UHD_LOG_ERROR(this->get_unique_id(), message) 229 #define RFNOC_LOG_FATAL(message) UHD_LOG_FATAL(this->get_unique_id(), message) 230 231 #ifndef UHD_LOG_FASTPATH_DISABLE 232 //! Extra-fast logging macro for when speed matters. 233 // No metadata is tracked. Only the message is displayed. This does not go 234 // through the regular backends. Mostly used for printing the UOSDL characters 235 // during streaming. 236 # define UHD_LOG_FASTPATH(message) uhd::_log::log_fastpath(message); 237 #else 238 # define UHD_LOG_FASTPATH(message) 239 #endif 240 241 // iostream-style logging 242 #define UHD_LOGGER_TRACE(component) _UHD_LOG_INTERNAL(component, uhd::log::trace) 243 #define UHD_LOGGER_DEBUG(component) _UHD_LOG_INTERNAL(component, uhd::log::debug) 244 #define UHD_LOGGER_INFO(component) _UHD_LOG_INTERNAL(component, uhd::log::info) 245 #define UHD_LOGGER_WARNING(component) _UHD_LOG_INTERNAL(component, uhd::log::warning) 246 #define UHD_LOGGER_ERROR(component) _UHD_LOG_INTERNAL(component, uhd::log::error) 247 #define UHD_LOGGER_FATAL(component) _UHD_LOG_INTERNAL(component, uhd::log::fatal) 248 249 250 #if defined(__GNUG__) 251 //! Helpful debug tool to print site info 252 # define UHD_HERE() \ 253 UHD_LOGGER_DEBUG("DEBUG") \ 254 << __FILE__ << ":" << __LINE__ << " (" << __PRETTY_FUNCTION__ << ")"; 255 #else 256 //! Helpful debug tool to print site info 257 # define UHD_HERE() UHD_LOGGER_DEBUG("DEBUG") << __FILE__ << ":" << __LINE__; 258 #endif 259 260 //! Helpful debug tool to print a variable 261 #define UHD_VAR(var) UHD_LOGGER_DEBUG("DEBUG") << #var << " = " << var; 262 263 //! Helpful debug tool to print a variable in hex 264 #define UHD_HEX(var) \ 265 UHD_LOGGER_DEBUG("DEBUG") << #var << " = 0x" << std::hex << std::setfill('0') \ 266 << std::setw(8) << var << std::dec; 267 268 //! \cond 269 namespace uhd { 270 namespace _log { 271 272 //! Fastpath logging 273 void UHD_API log_fastpath(const std::string&); 274 275 //! Internal logging object (called by UHD_LOG* macros) 276 class UHD_API log 277 { 278 public: 279 log(const uhd::log::severity_level verbosity, 280 const std::string& file, 281 const unsigned int line, 282 const std::string& component, 283 const boost::thread::id thread_id); 284 285 ~log(void); 286 287 // Macro for overloading insertion operators to avoid costly 288 // conversion of types if not logging. 289 #define INSERTION_OVERLOAD(x) \ 290 log& operator<<(x) \ 291 { \ 292 if (_log_it) { \ 293 _ss << val; \ 294 } \ 295 return *this; \ 296 } 297 298 // General insertion overload 299 template <typename T> 300 INSERTION_OVERLOAD(T val) 301 302 // Insertion overloads for std::ostream manipulators 303 INSERTION_OVERLOAD(std::ostream& (*val)(std::ostream&)) 304 INSERTION_OVERLOAD(std::ios& (*val)(std::ios&)) 305 INSERTION_OVERLOAD(std::ios_base& (*val)(std::ios_base&)) 306 307 private : uhd::log::logging_info _log_info; 308 std::ostringstream _ss; 309 const bool _log_it; 310 }; 311 312 } // namespace _log 313 //! \endcond 314 } /* namespace uhd */ 315