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_GLE(M)(sev [, mod]) attempt to add a string description of the 45 // HRESULT returned by GetLastError. The "M" variant allows searching of a 46 // DLL's string table for the error description. 47 // LOG_ERRNO(sev) attempts to add a string description of an errno-derived 48 // error. errno and associated facilities exist on both Windows and POSIX, 49 // but on Windows they only apply to the C/C++ runtime. 50 // LOG_ERR(sev) is an alias for the platform's normal error system, i.e. _GLE on 51 // Windows and _ERRNO on POSIX. 52 // (The above three also all have _EX versions that let you specify the error 53 // code, rather than using the last one.) 54 // LOG_E(sev, ctx, err, ...) logs a detailed error interpreted using the 55 // specified context. 56 // LOG_CHECK_LEVEL(sev) (and LOG_CHECK_LEVEL_V(sev)) can be used as a test 57 // before performing expensive or sensitive operations whose sole purpose is 58 // to output logging data at the desired level. 59 // Lastly, PLOG(sev, err) is an alias for LOG_ERR_EX. 60 61 #ifndef TALK_BASE_LOGGING_H_ 62 #define TALK_BASE_LOGGING_H_ 63 64 #ifdef HAVE_CONFIG_H 65 #include "config.h" // NOLINT 66 #endif 67 68 #include <list> 69 #include <sstream> 70 #include <string> 71 #include <utility> 72 #include "talk/base/basictypes.h" 73 #include "talk/base/criticalsection.h" 74 75 namespace talk_base { 76 77 class StreamInterface; 78 79 /////////////////////////////////////////////////////////////////////////////// 80 // ConstantLabel can be used to easily generate string names from constant 81 // values. This can be useful for logging descriptive names of error messages. 82 // Usage: 83 // const ConstantLabel LIBRARY_ERRORS[] = { 84 // KLABEL(SOME_ERROR), 85 // KLABEL(SOME_OTHER_ERROR), 86 // ... 87 // LASTLABEL 88 // } 89 // 90 // int err = LibraryFunc(); 91 // LOG(LS_ERROR) << "LibraryFunc returned: " 92 // << ErrorName(err, LIBRARY_ERRORS); 93 94 struct ConstantLabel { int value; const char * label; }; 95 #define KLABEL(x) { x, #x } 96 #define TLABEL(x, y) { x, y } 97 #define LASTLABEL { 0, 0 } 98 99 const char * FindLabel(int value, const ConstantLabel entries[]); 100 std::string ErrorName(int err, const ConstantLabel* err_table); 101 102 ////////////////////////////////////////////////////////////////////// 103 104 // Note that the non-standard LoggingSeverity aliases exist because they are 105 // still in broad use. The meanings of the levels are: 106 // LS_SENSITIVE: Information which should only be logged with the consent 107 // of the user, due to privacy concerns. 108 // LS_VERBOSE: This level is for data which we do not want to appear in the 109 // normal debug log, but should appear in diagnostic logs. 110 // LS_INFO: Chatty level used in debugging for all sorts of things, the default 111 // in debug builds. 112 // LS_WARNING: Something that may warrant investigation. 113 // LS_ERROR: Something that should not have occurred. 114 enum LoggingSeverity { LS_SENSITIVE, LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR, 115 INFO = LS_INFO, 116 WARNING = LS_WARNING, 117 LERROR = LS_ERROR }; 118 119 // LogErrorContext assists in interpreting the meaning of an error value. 120 enum LogErrorContext { 121 ERRCTX_NONE, 122 ERRCTX_ERRNO, // System-local errno 123 ERRCTX_HRESULT, // Windows HRESULT 124 ERRCTX_OSSTATUS, // MacOS OSStatus 125 126 // Abbreviations for LOG_E macro 127 ERRCTX_EN = ERRCTX_ERRNO, // LOG_E(sev, EN, x) 128 ERRCTX_HR = ERRCTX_HRESULT, // LOG_E(sev, HR, x) 129 ERRCTX_OS = ERRCTX_OSSTATUS, // LOG_E(sev, OS, x) 130 }; 131 132 class LogMessage { 133 public: 134 static const int NO_LOGGING; 135 136 LogMessage(const char* file, int line, LoggingSeverity sev, 137 LogErrorContext err_ctx = ERRCTX_NONE, int err = 0, 138 const char* module = NULL); 139 ~LogMessage(); 140 141 static inline bool Loggable(LoggingSeverity sev) { return (sev >= min_sev_); } 142 std::ostream& stream() { return print_stream_; } 143 144 // These are attributes which apply to all logging channels 145 // LogContext: Display the file and line number of the message 146 static void LogContext(int min_sev); 147 // LogThreads: Display the thread identifier of the current thread 148 static void LogThreads(bool on = true); 149 // LogTimestamps: Display the elapsed time of the program 150 static void LogTimestamps(bool on = true); 151 152 // Timestamps begin with program execution, but can be reset with this 153 // function for measuring the duration of an activity, or to synchronize 154 // timestamps between multiple instances. 155 static void ResetTimestamps(); 156 157 // These are the available logging channels 158 // Debug: Debug console on Windows, otherwise stderr 159 static void LogToDebug(int min_sev); 160 static int GetLogToDebug() { return dbg_sev_; } 161 162 // Stream: Any non-blocking stream interface. LogMessage takes ownership of 163 // the stream. Multiple streams may be specified by using AddLogToStream. 164 // LogToStream is retained for backwards compatibility; when invoked, it 165 // will discard any previously set streams and install the specified stream. 166 // GetLogToStream gets the severity for the specified stream, of if none 167 // is specified, the minimum stream severity. 168 // RemoveLogToStream removes the specified stream, without destroying it. 169 static void LogToStream(StreamInterface* stream, int min_sev); 170 static int GetLogToStream(StreamInterface* stream = NULL); 171 static void AddLogToStream(StreamInterface* stream, int min_sev); 172 static void RemoveLogToStream(StreamInterface* stream); 173 174 // Testing against MinLogSeverity allows code to avoid potentially expensive 175 // logging operations by pre-checking the logging level. 176 static int GetMinLogSeverity() { return min_sev_; } 177 178 static void SetDiagnosticMode(bool f) { is_diagnostic_mode_ = f; } 179 static bool IsDiagnosticMode() { return is_diagnostic_mode_; } 180 181 // Parses the provided parameter stream to configure the options above. 182 // Useful for configuring logging from the command line. If file logging 183 // is enabled, it is output to the specified filename. 184 static void ConfigureLogging(const char* params, const char* filename); 185 186 // Convert the string to a LS_ value; also accept numeric values. 187 static int ParseLogSeverity(const std::string& value); 188 189 private: 190 typedef std::list<std::pair<StreamInterface*, int> > StreamList; 191 192 // Updates min_sev_ appropriately when debug sinks change. 193 static void UpdateMinLogSeverity(); 194 195 // These assist in formatting some parts of the debug output. 196 static const char* Describe(LoggingSeverity sev); 197 static const char* DescribeFile(const char* file); 198 199 // These write out the actual log messages. 200 static void OutputToDebug(const std::string& msg, LoggingSeverity severity_); 201 static void OutputToStream(StreamInterface* stream, const std::string& msg); 202 203 // The ostream that buffers the formatted message before output 204 std::ostringstream print_stream_; 205 206 // The severity level of this message 207 LoggingSeverity severity_; 208 209 // String data generated in the constructor, that should be appended to 210 // the message before output. 211 std::string extra_; 212 213 // Global lock for the logging subsystem 214 static CriticalSection crit_; 215 216 // dbg_sev_ is the thresholds for those output targets 217 // min_sev_ is the minimum (most verbose) of those levels, and is used 218 // as a short-circuit in the logging macros to identify messages that won't 219 // be logged. 220 // ctx_sev_ is the minimum level at which file context is displayed 221 static int min_sev_, dbg_sev_, ctx_sev_; 222 223 // The output streams and their associated severities 224 static StreamList streams_; 225 226 // Flags for formatting options 227 static bool thread_, timestamp_; 228 229 // The timestamp at which logging started. 230 static uint32 start_; 231 232 // are we in diagnostic mode (as defined by the app)? 233 static bool is_diagnostic_mode_; 234 235 DISALLOW_EVIL_CONSTRUCTORS(LogMessage); 236 }; 237 238 ////////////////////////////////////////////////////////////////////// 239 // Logging Helpers 240 ////////////////////////////////////////////////////////////////////// 241 242 class LogMultilineState { 243 public: 244 size_t unprintable_count_[2]; 245 LogMultilineState() { 246 unprintable_count_[0] = unprintable_count_[1] = 0; 247 } 248 }; 249 250 // When possible, pass optional state variable to track various data across 251 // multiple calls to LogMultiline. Otherwise, pass NULL. 252 void LogMultiline(LoggingSeverity level, const char* label, bool input, 253 const void* data, size_t len, bool hex_mode, 254 LogMultilineState* state); 255 256 ////////////////////////////////////////////////////////////////////// 257 // Macros which automatically disable logging when LOGGING == 0 258 ////////////////////////////////////////////////////////////////////// 259 260 // If LOGGING is not explicitly defined, default to enabled in debug mode 261 #if !defined(LOGGING) 262 #if defined(_DEBUG) && !defined(NDEBUG) 263 #define LOGGING 1 264 #else 265 #define LOGGING 0 266 #endif 267 #endif // !defined(LOGGING) 268 269 #ifndef LOG 270 #if LOGGING 271 272 // The following non-obvious technique for implementation of a 273 // conditional log stream was stolen from google3/base/logging.h. 274 275 // This class is used to explicitly ignore values in the conditional 276 // logging macros. This avoids compiler warnings like "value computed 277 // is not used" and "statement has no effect". 278 279 class LogMessageVoidify { 280 public: 281 LogMessageVoidify() { } 282 // This has to be an operator with a precedence lower than << but 283 // higher than ?: 284 void operator&(std::ostream&) { } 285 }; 286 287 #define LOG_SEVERITY_PRECONDITION(sev) \ 288 !(talk_base::LogMessage::Loggable(sev)) \ 289 ? (void) 0 \ 290 : talk_base::LogMessageVoidify() & 291 292 #define LOG(sev) \ 293 LOG_SEVERITY_PRECONDITION(talk_base::sev) \ 294 talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev).stream() 295 296 // The _V version is for when a variable is passed in. It doesn't do the 297 // namespace concatination. 298 #define LOG_V(sev) \ 299 LOG_SEVERITY_PRECONDITION(sev) \ 300 talk_base::LogMessage(__FILE__, __LINE__, sev).stream() 301 302 // The _F version prefixes the message with the current function name. 303 #if defined(__GNUC__) && defined(_DEBUG) 304 #define LOG_F(sev) LOG(sev) << __PRETTY_FUNCTION__ << ": " 305 #else 306 #define LOG_F(sev) LOG(sev) << __FUNCTION__ << ": " 307 #endif 308 309 #define LOG_CHECK_LEVEL(sev) \ 310 talk_base::LogCheckLevel(talk_base::sev) 311 #define LOG_CHECK_LEVEL_V(sev) \ 312 talk_base::LogCheckLevel(sev) 313 inline bool LogCheckLevel(LoggingSeverity sev) { 314 return (LogMessage::GetMinLogSeverity() <= sev); 315 } 316 317 #define LOG_E(sev, ctx, err, ...) \ 318 LOG_SEVERITY_PRECONDITION(talk_base::sev) \ 319 talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev, \ 320 talk_base::ERRCTX_ ## ctx, err , ##__VA_ARGS__) \ 321 .stream() 322 323 #else // !LOGGING 324 325 // Hopefully, the compiler will optimize away some of this code. 326 // Note: syntax of "1 ? (void)0 : LogMessage" was causing errors in g++, 327 // converted to "while (false)" 328 #define LOG(sev) \ 329 while (false)talk_base:: LogMessage(NULL, 0, talk_base::sev).stream() 330 #define LOG_V(sev) \ 331 while (false) talk_base::LogMessage(NULL, 0, sev).stream() 332 #define LOG_F(sev) LOG(sev) << __FUNCTION__ << ": " 333 #define LOG_CHECK_LEVEL(sev) \ 334 false 335 #define LOG_CHECK_LEVEL_V(sev) \ 336 false 337 338 #define LOG_E(sev, ctx, err, ...) \ 339 while (false) talk_base::LogMessage(__FILE__, __LINE__, talk_base::sev, \ 340 talk_base::ERRCTX_ ## ctx, err , ##__VA_ARGS__) \ 341 .stream() 342 343 #endif // !LOGGING 344 345 #define LOG_ERRNO_EX(sev, err) \ 346 LOG_E(sev, ERRNO, err) 347 #define LOG_ERRNO(sev) \ 348 LOG_ERRNO_EX(sev, errno) 349 350 #ifdef WIN32 351 #define LOG_GLE_EX(sev, err) \ 352 LOG_E(sev, HRESULT, err) 353 #define LOG_GLE(sev) \ 354 LOG_GLE_EX(sev, GetLastError()) 355 #define LOG_GLEM(sev, mod) \ 356 LOG_E(sev, HRESULT, GetLastError(), mod) 357 #define LOG_ERR_EX(sev, err) \ 358 LOG_GLE_EX(sev, err) 359 #define LOG_ERR(sev) \ 360 LOG_GLE(sev) 361 #define LAST_SYSTEM_ERROR \ 362 (::GetLastError()) 363 #elif POSIX 364 #define LOG_ERR_EX(sev, err) \ 365 LOG_ERRNO_EX(sev, err) 366 #define LOG_ERR(sev) \ 367 LOG_ERRNO(sev) 368 #define LAST_SYSTEM_ERROR \ 369 (errno) 370 #endif // WIN32 371 372 #define PLOG(sev, err) \ 373 LOG_ERR_EX(sev, err) 374 375 // TODO(?): Add an "assert" wrapper that logs in the same manner. 376 377 #endif // LOG 378 379 } // namespace talk_base 380 381 #endif // TALK_BASE_LOGGING_H_ 382