1 /* 2 * libjingle 3 * Copyright 2004--2005, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 // LOG(...) an ostream target that can be used to send formatted 29 // output to a variety of logging targets, such as debugger console, stderr, 30 // file, or any StreamInterface. 31 // The severity level passed as the first argument to the LOGging 32 // functions is used as a filter, to limit the verbosity of the logging. 33 // Static members of LogMessage documented below are used to control the 34 // verbosity and target of the output. 35 // There are several variations on the LOG macro which facilitate logging 36 // of common error conditions, detailed below. 37 38 // LOG(sev) logs the given stream at severity "sev", which must be a 39 // compile-time constant of the LoggingSeverity type, without the namespace 40 // prefix. 41 // LOG_V(sev) Like LOG(), but sev is a run-time variable of the LoggingSeverity 42 // type (basically, it just doesn't prepend the namespace). 43 // LOG_F(sev) Like LOG(), but includes the name of the current function. 44 // LOG_T(sev) Like LOG(), but includes the this pointer. 45 // LOG_T_F(sev) Like LOG_F(), but includes the this pointer. 46 // LOG_GLE(M)(sev [, mod]) attempt to add a string description of the 47 // HRESULT returned by GetLastError. The "M" variant allows searching of a 48 // DLL's string table for the error description. 49 // LOG_ERRNO(sev) attempts to add a string description of an errno-derived 50 // error. errno and associated facilities exist on both Windows and POSIX, 51 // but on Windows they only apply to the C/C++ runtime. 52 // LOG_ERR(sev) is an alias for the platform's normal error system, i.e. _GLE on 53 // Windows and _ERRNO on POSIX. 54 // (The above three also all have _EX versions that let you specify the error 55 // code, rather than using the last one.) 56 // LOG_E(sev, ctx, err, ...) logs a detailed error interpreted using the 57 // specified context. 58 // LOG_CHECK_LEVEL(sev) (and LOG_CHECK_LEVEL_V(sev)) can be used as a test 59 // before performing expensive or sensitive operations whose sole purpose is 60 // to output logging data at the desired level. 61 // Lastly, PLOG(sev, err) is an alias for LOG_ERR_EX. 62 63 #ifndef TALK_BASE_LOGGING_H_ 64 #define TALK_BASE_LOGGING_H_ 65 66 #ifdef HAVE_CONFIG_H 67 #include "config.h" // NOLINT 68 #endif 69 70 #include <list> 71 #include <sstream> 72 #include <string> 73 #include <utility> 74 #include "talk/base/basictypes.h" 75 #include "talk/base/criticalsection.h" 76 77 namespace talk_base { 78 79 class StreamInterface; 80 81 /////////////////////////////////////////////////////////////////////////////// 82 // ConstantLabel can be used to easily generate string names from constant 83 // values. This can be useful for logging descriptive names of error messages. 84 // Usage: 85 // const ConstantLabel LIBRARY_ERRORS[] = { 86 // KLABEL(SOME_ERROR), 87 // KLABEL(SOME_OTHER_ERROR), 88 // ... 89 // LASTLABEL 90 // } 91 // 92 // int err = LibraryFunc(); 93 // LOG(LS_ERROR) << "LibraryFunc returned: " 94 // << ErrorName(err, LIBRARY_ERRORS); 95 96 struct ConstantLabel { int value; const char * label; }; 97 #define KLABEL(x) { x, #x } 98 #define TLABEL(x, y) { x, y } 99 #define LASTLABEL { 0, 0 } 100 101 const char * FindLabel(int value, const ConstantLabel entries[]); 102 std::string ErrorName(int err, const ConstantLabel* err_table); 103 104 ////////////////////////////////////////////////////////////////////// 105 106 // Note that the non-standard LoggingSeverity aliases exist because they are 107 // still in broad use. The meanings of the levels are: 108 // LS_SENSITIVE: Information which should only be logged with the consent 109 // of the user, due to privacy concerns. 110 // LS_VERBOSE: This level is for data which we do not want to appear in the 111 // normal debug log, but should appear in diagnostic logs. 112 // LS_INFO: Chatty level used in debugging for all sorts of things, the default 113 // in debug builds. 114 // LS_WARNING: Something that may warrant investigation. 115 // LS_ERROR: Something that should not have occurred. 116 enum LoggingSeverity { LS_SENSITIVE, LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR, 117 INFO = LS_INFO, 118 WARNING = LS_WARNING, 119 LERROR = LS_ERROR }; 120 121 // LogErrorContext assists in interpreting the meaning of an error value. 122 enum LogErrorContext { 123 ERRCTX_NONE, 124 ERRCTX_ERRNO, // System-local errno 125 ERRCTX_HRESULT, // Windows HRESULT 126 ERRCTX_OSSTATUS, // MacOS OSStatus 127 128 // Abbreviations for LOG_E macro 129 ERRCTX_EN = ERRCTX_ERRNO, // LOG_E(sev, EN, x) 130 ERRCTX_HR = ERRCTX_HRESULT, // LOG_E(sev, HR, x) 131 ERRCTX_OS = ERRCTX_OSSTATUS, // LOG_E(sev, OS, x) 132 }; 133 134 class LogMessage { 135 public: 136 static const int NO_LOGGING; 137 static const uint32 WARN_SLOW_LOGS_DELAY = 50; // ms 138 139 LogMessage(const char* file, int line, LoggingSeverity sev, 140 LogErrorContext err_ctx = ERRCTX_NONE, int err = 0, 141 const char* module = NULL); 142 ~LogMessage(); 143 144 static inline bool Loggable(LoggingSeverity sev) { return (sev >= min_sev_); } 145 std::ostream& stream() { return print_stream_; } 146 147 // Returns the time at which this function was called for the first time. 148 // The time will be used as the logging start time. 149 // If this is not called externally, the LogMessage ctor also calls it, in 150 // which case the logging start time will be the time of the first LogMessage 151 // instance is created. 152 static uint32 LogStartTime(); 153 154 // Returns the wall clock equivalent of |LogStartTime|, in seconds from the 155 // epoch. 156 static uint32 WallClockStartTime(); 157 158 // These are attributes which apply to all logging channels 159 // LogContext: Display the file and line number of the message 160 static void LogContext(int min_sev); 161 // LogThreads: Display the thread identifier of the current thread 162 static void LogThreads(bool on = true); 163 // LogTimestamps: Display the elapsed time of the program 164 static void LogTimestamps(bool on = true); 165 166 // These are the available logging channels 167 // Debug: Debug console on Windows, otherwise stderr 168 static void LogToDebug(int min_sev); 169 static int GetLogToDebug() { return dbg_sev_; } 170 171 // Stream: Any non-blocking stream interface. LogMessage takes ownership of 172 // the stream. Multiple streams may be specified by using AddLogToStream. 173 // LogToStream is retained for backwards compatibility; when invoked, it 174 // will discard any previously set streams and install the specified stream. 175 // GetLogToStream gets the severity for the specified stream, of if none 176 // is specified, the minimum stream severity. 177 // RemoveLogToStream removes the specified stream, without destroying it. 178 static void LogToStream(StreamInterface* stream, int min_sev); 179 static int GetLogToStream(StreamInterface* stream = NULL); 180 static void AddLogToStream(StreamInterface* stream, int min_sev); 181 static void RemoveLogToStream(StreamInterface* stream); 182 183 // Testing against MinLogSeverity allows code to avoid potentially expensive 184 // logging operations by pre-checking the logging level. 185 static int GetMinLogSeverity() { return min_sev_; } 186 187 static void SetDiagnosticMode(bool f) { is_diagnostic_mode_ = f; } 188 static bool IsDiagnosticMode() { return is_diagnostic_mode_; } 189 190 // Parses the provided parameter stream to configure the options above. 191 // Useful for configuring logging from the command line. If file logging 192 // is enabled, it is output to the specified filename. 193 static void ConfigureLogging(const char* params, const char* filename); 194 195 // Convert the string to a LS_ value; also accept numeric values. 196 static int ParseLogSeverity(const std::string& value); 197 198 private: 199 typedef std::list<std::pair<StreamInterface*, int> > StreamList; 200 201 // Updates min_sev_ appropriately when debug sinks change. 202 static void UpdateMinLogSeverity(); 203 204 // These assist in formatting some parts of the debug output. 205 static const char* Describe(LoggingSeverity sev); 206 static const char* DescribeFile(const char* file); 207 208 // These write out the actual log messages. 209 static void OutputToDebug(const std::string& msg, LoggingSeverity severity_); 210 static void OutputToStream(StreamInterface* stream, const std::string& msg); 211 212 // The ostream that buffers the formatted message before output 213 std::ostringstream print_stream_; 214 215 // The severity level of this message 216 LoggingSeverity severity_; 217 218 // String data generated in the constructor, that should be appended to 219 // the message before output. 220 std::string extra_; 221 222 // If time it takes to write to stream is more than this, log one 223 // additional warning about it. 224 uint32 warn_slow_logs_delay_; 225 226 // Global lock for the logging subsystem 227 static CriticalSection crit_; 228 229 // dbg_sev_ is the thresholds for those output targets 230 // min_sev_ is the minimum (most verbose) of those levels, and is used 231 // as a short-circuit in the logging macros to identify messages that won't 232 // be logged. 233 // ctx_sev_ is the minimum level at which file context is displayed 234 static int min_sev_, dbg_sev_, ctx_sev_; 235 236 // The output streams and their associated severities 237 static StreamList streams_; 238 239 // Flags for formatting options 240 static bool thread_, timestamp_; 241 242 // are we in diagnostic mode (as defined by the app)? 243 static bool is_diagnostic_mode_; 244 245 DISALLOW_EVIL_CONSTRUCTORS(LogMessage); 246 }; 247 248 ////////////////////////////////////////////////////////////////////// 249 // Logging Helpers 250 ////////////////////////////////////////////////////////////////////// 251 252 class LogMultilineState { 253 public: 254 size_t unprintable_count_[2]; 255 LogMultilineState() { 256 unprintable_count_[0] = unprintable_count_[1] = 0; 257 } 258 }; 259 260 // When possible, pass optional state variable to track various data across 261 // multiple calls to LogMultiline. Otherwise, pass NULL. 262 void LogMultiline(LoggingSeverity level, const char* label, bool input, 263 const void* data, size_t len, bool hex_mode, 264 LogMultilineState* state); 265 266 ////////////////////////////////////////////////////////////////////// 267 // Macros which automatically disable logging when LOGGING == 0 268 ////////////////////////////////////////////////////////////////////// 269 270 // If LOGGING is not explicitly defined, default to enabled in debug mode 271 #if !defined(LOGGING) 272 #if defined(_DEBUG) && !defined(NDEBUG) 273 #define LOGGING 1 274 #else 275 #define LOGGING 0 276 #endif 277 #endif // !defined(LOGGING) 278 279 #ifndef LOG 280 #if LOGGING 281 282 // The following non-obvious technique for implementation of a 283 // conditional log stream was stolen from google3/base/logging.h. 284 285 // This class is used to explicitly ignore values in the conditional 286 // logging macros. This avoids compiler warnings like "value computed 287 // is not used" and "statement has no effect". 288 289 class LogMessageVoidify { 290 public: 291 LogMessageVoidify() { } 292 // This has to be an operator with a precedence lower than << but 293 // higher than ?: 294 void operator&(std::ostream&) { } 295 }; 296 297 #define LOG_SEVERITY_PRECONDITION(sev) \ 298 !(talk_base::LogMessage::Loggable(sev)) \ 299 ? (void) 0 \ 300 : talk_base::LogMessageVoidify() & 301 302 #define LOG(sev) \ 303 LOG_SEVERITY_PRECONDITION(talk_base::sev) \ 304 talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev).stream() 305 306 // The _V version is for when a variable is passed in. It doesn't do the 307 // namespace concatination. 308 #define LOG_V(sev) \ 309 LOG_SEVERITY_PRECONDITION(sev) \ 310 talk_base::LogMessage(__FILE__, __LINE__, sev).stream() 311 312 // The _F version prefixes the message with the current function name. 313 #if (defined(__GNUC__) && defined(_DEBUG)) || defined(WANT_PRETTY_LOG_F) 314 #define LOG_F(sev) LOG(sev) << __PRETTY_FUNCTION__ << ": " 315 #define LOG_T_F(sev) LOG(sev) << this << ": " << __PRETTY_FUNCTION__ << ": " 316 #else 317 #define LOG_F(sev) LOG(sev) << __FUNCTION__ << ": " 318 #define LOG_T_F(sev) LOG(sev) << this << ": " << __FUNCTION__ << ": " 319 #endif 320 321 #define LOG_CHECK_LEVEL(sev) \ 322 talk_base::LogCheckLevel(talk_base::sev) 323 #define LOG_CHECK_LEVEL_V(sev) \ 324 talk_base::LogCheckLevel(sev) 325 inline bool LogCheckLevel(LoggingSeverity sev) { 326 return (LogMessage::GetMinLogSeverity() <= sev); 327 } 328 329 #define LOG_E(sev, ctx, err, ...) \ 330 LOG_SEVERITY_PRECONDITION(talk_base::sev) \ 331 talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev, \ 332 talk_base::ERRCTX_ ## ctx, err , ##__VA_ARGS__) \ 333 .stream() 334 335 #define LOG_T(sev) LOG(sev) << this << ": " 336 337 #else // !LOGGING 338 339 // Hopefully, the compiler will optimize away some of this code. 340 // Note: syntax of "1 ? (void)0 : LogMessage" was causing errors in g++, 341 // converted to "while (false)" 342 #define LOG(sev) \ 343 while (false)talk_base:: LogMessage(NULL, 0, talk_base::sev).stream() 344 #define LOG_V(sev) \ 345 while (false) talk_base::LogMessage(NULL, 0, sev).stream() 346 #define LOG_F(sev) LOG(sev) << __FUNCTION__ << ": " 347 #define LOG_CHECK_LEVEL(sev) \ 348 false 349 #define LOG_CHECK_LEVEL_V(sev) \ 350 false 351 352 #define LOG_E(sev, ctx, err, ...) \ 353 while (false) talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev, \ 354 talk_base::ERRCTX_ ## ctx, err , ##__VA_ARGS__) \ 355 .stream() 356 357 #define LOG_T(sev) LOG(sev) << this << ": " 358 #define LOG_T_F(sev) LOG(sev) << this << ": " << __FUNCTION__ << 359 #endif // !LOGGING 360 361 #define LOG_ERRNO_EX(sev, err) \ 362 LOG_E(sev, ERRNO, err) 363 #define LOG_ERRNO(sev) \ 364 LOG_ERRNO_EX(sev, errno) 365 366 #ifdef WIN32 367 #define LOG_GLE_EX(sev, err) \ 368 LOG_E(sev, HRESULT, err) 369 #define LOG_GLE(sev) \ 370 LOG_GLE_EX(sev, GetLastError()) 371 #define LOG_GLEM(sev, mod) \ 372 LOG_E(sev, HRESULT, GetLastError(), mod) 373 #define LOG_ERR_EX(sev, err) \ 374 LOG_GLE_EX(sev, err) 375 #define LOG_ERR(sev) \ 376 LOG_GLE(sev) 377 #define LAST_SYSTEM_ERROR \ 378 (::GetLastError()) 379 #elif POSIX 380 #define LOG_ERR_EX(sev, err) \ 381 LOG_ERRNO_EX(sev, err) 382 #define LOG_ERR(sev) \ 383 LOG_ERRNO(sev) 384 #define LAST_SYSTEM_ERROR \ 385 (errno) 386 #endif // WIN32 387 388 #define PLOG(sev, err) \ 389 LOG_ERR_EX(sev, err) 390 391 // TODO(?): Add an "assert" wrapper that logs in the same manner. 392 393 #endif // LOG 394 395 } // namespace talk_base 396 397 #endif // TALK_BASE_LOGGING_H_ 398