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