From 4b4afc9a78dcf44a42cda4ff509299e164acae54 Mon Sep 17 00:00:00 2001 From: "tschmelcher@google.com" Date: Tue, 6 Oct 2009 22:14:38 +0000 Subject: Add logging macros that automatically append the last system error in string form. TESTED=Linux: tested PLOG and DPLOG with both a valid error and invalid error on a dbg build with both the default strerror_r implementation (GNU) and the other one (POSIX) via some throw-away macro evilness, and also tested the default strerror_r again on an opt build to verify DPLOG is a no-op; Windows: tested PLOG and DPLOG with both a valid error and invalid error on a dbg build; also tested LOG_GETLASTERROR_MODULE with winhttp and ERROR_WINHTTP_CANNOT_CONNECT and verified that it prints the correct system message and that it doesn't with PLOG; also tested LOG_GETLASTERROR_MODULE with a bogus module name and verified that it prints an error that it can't find the module, and the original error; Mac: none (implicitly tested via the Linux POSIX tests) Review URL: http://codereview.chromium.org/255093 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28166 0039d316-1c4b-4281-b951-d872f2087c98 --- base/logging.h | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 142 insertions(+), 8 deletions(-) (limited to 'base/logging.h') diff --git a/base/logging.h b/base/logging.h index a1d439c..f117200 100644 --- a/base/logging.h +++ b/base/logging.h @@ -75,6 +75,14 @@ // // We also override the standard 'assert' to use 'DLOG_ASSERT'. // +// Lastly, there is: +// +// PLOG(ERROR) << "Couldn't do foo"; +// DPLOG(ERROR) << "Couldn't do foo"; +// +// which appends the last system error to the message in string form (taken from +// GetLastError() on Windows and errno on POSIX). +// // The supported severity levels for macros that allow you to specify one // are (in increasing order of severity) INFO, WARNING, ERROR, ERROR_REPORT, // and FATAL. @@ -192,18 +200,33 @@ const LogSeverity LOG_DFATAL_LEVEL = LOG_FATAL; // A few definitions of macros that don't generate much code. These are used // by LOG() and LOG_IF, etc. Since these are used all over our code, it's // better to have compact code for these operations. +#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_INFO , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_WARNING , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_ERROR , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, \ + logging::LOG_ERROR_REPORT , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_FATAL , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, \ + logging::LOG_DFATAL_LEVEL , ##__VA_ARGS__) + #define COMPACT_GOOGLE_LOG_INFO \ - logging::LogMessage(__FILE__, __LINE__) + COMPACT_GOOGLE_LOG_EX_INFO(LogMessage) #define COMPACT_GOOGLE_LOG_WARNING \ - logging::LogMessage(__FILE__, __LINE__, logging::LOG_WARNING) + COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage) #define COMPACT_GOOGLE_LOG_ERROR \ - logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR) + COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage) #define COMPACT_GOOGLE_LOG_ERROR_REPORT \ - logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR_REPORT) + COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(LogMessage) #define COMPACT_GOOGLE_LOG_FATAL \ - logging::LogMessage(__FILE__, __LINE__, logging::LOG_FATAL) + COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage) #define COMPACT_GOOGLE_LOG_DFATAL \ - logging::LogMessage(__FILE__, __LINE__, logging::LOG_DFATAL_LEVEL) + COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage) // wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets // substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us @@ -211,8 +234,9 @@ const LogSeverity LOG_DFATAL_LEVEL = LOG_FATAL; // as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that // the Windows SDK does for consistency. #define ERROR 0 -#define COMPACT_GOOGLE_LOG_0 \ - logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR) +#define COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \ + COMPACT_GOOGLE_LOG_EX_ERROR(ClassName , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR // We use the preprocessor's merging operator, "##", so that, e.g., // LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO. There's some funny @@ -235,6 +259,26 @@ const LogSeverity LOG_DFATAL_LEVEL = LOG_FATAL; #define SYSLOG_ASSERT(condition) \ SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". " +#if defined(OS_WIN) +#define LOG_GETLASTERROR(severity) \ + COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \ + ::logging::GetLastSystemErrorCode()).stream() +#define LOG_GETLASTERROR_MODULE(severity, module) \ + COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \ + ::logging::GetLastSystemErrorCode(), module).stream() +// PLOG is the usual error logging macro for each platform. +#define PLOG(severity) LOG_GETLASTERROR(severity) +#define DPLOG(severity) DLOG_GETLASTERROR(severity) +#elif defined(OS_POSIX) +#define LOG_ERRNO(severity) \ + COMPACT_GOOGLE_LOG_EX_ ## severity(ErrnoLogMessage, \ + ::logging::GetLastSystemErrorCode()).stream() +// PLOG is the usual error logging macro for each platform. +#define PLOG(severity) LOG_ERRNO(severity) +#define DPLOG(severity) DLOG_ERRNO(severity) +// TODO(tschmelcher): Should we add OSStatus logging for Mac? +#endif + // CHECK dies with a fatal error if condition is not true. It is *not* // controlled by NDEBUG, so the check will be executed regardless of // compilation mode. @@ -301,6 +345,17 @@ std::string* MakeCheckOpString(const int& v1, #define DLOG_ASSERT(condition) \ true ? (void) 0 : LOG_ASSERT(condition) +#if defined(OS_WIN) +#define DLOG_GETLASTERROR(severity) \ + true ? (void) 0 : logging::LogMessageVoidify() & LOG_GETLASTERROR(severity) +#define DLOG_GETLASTERROR_MODULE(severity, module) \ + true ? (void) 0 : logging::LogMessageVoidify() & \ + LOG_GETLASTERROR_MODULE(severity, module) +#elif defined(OS_POSIX) +#define DLOG_ERRNO(severity) \ + true ? (void) 0 : logging::LogMessageVoidify() & LOG_ERRNO(severity) +#endif + enum { DEBUG_MODE = 0 }; // This macro can be followed by a sequence of stream parameters in @@ -354,6 +409,14 @@ enum { DEBUG_MODE = 0 }; #define DLOG_IF(severity, condition) LOG_IF(severity, condition) #define DLOG_ASSERT(condition) LOG_ASSERT(condition) +#if defined(OS_WIN) +#define DLOG_GETLASTERROR(severity) LOG_GETLASTERROR(severity) +#define DLOG_GETLASTERROR_MODULE(severity, module) \ + LOG_GETLASTERROR_MODULE(severity, module) +#elif defined(OS_POSIX) +#define DLOG_ERRNO(severity) LOG_ERRNO(severity) +#endif + // debug-only checking. not executed in NDEBUG mode. enum { DEBUG_MODE = 1 }; #define DCHECK(condition) \ @@ -413,6 +476,17 @@ DECLARE_DCHECK_STROP_IMPL(_stricmp, false) #define DLOG_ASSERT(condition) \ true ? (void) 0 : LOG_ASSERT(condition) +#if defined(OS_WIN) +#define DLOG_GETLASTERROR(severity) \ + true ? (void) 0 : logging::LogMessageVoidify() & LOG_GETLASTERROR(severity) +#define DLOG_GETLASTERROR_MODULE(severity, module) \ + true ? (void) 0 : logging::LogMessageVoidify() & \ + LOG_GETLASTERROR_MODULE(severity, module) +#elif defined(OS_POSIX) +#define DLOG_ERRNO(severity) \ + true ? (void) 0 : logging::LogMessageVoidify() & LOG_ERRNO(severity) +#endif + enum { DEBUG_MODE = 0 }; // This macro can be followed by a sequence of stream parameters in @@ -597,6 +671,66 @@ class LogMessageVoidify { void operator&(std::ostream&) { } }; +#if defined(OS_WIN) +typedef unsigned long SystemErrorCode; +#elif defined(OS_POSIX) +typedef int SystemErrorCode; +#endif + +// Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to +// pull in windows.h just for GetLastError() and DWORD. +SystemErrorCode GetLastSystemErrorCode(); + +#if defined(OS_WIN) +// Appends a formatted system message of the GetLastError() type. +class Win32ErrorLogMessage { + public: + Win32ErrorLogMessage(const char* file, + int line, + LogSeverity severity, + SystemErrorCode err, + const char* module); + + Win32ErrorLogMessage(const char* file, + int line, + LogSeverity severity, + SystemErrorCode err); + + std::ostream& stream() { return log_message_.stream(); } + + // Appends the error message before destructing the encapsulated class. + ~Win32ErrorLogMessage(); + + private: + SystemErrorCode err_; + // Optional name of the module defining the error. + const char* module_; + LogMessage log_message_; + + DISALLOW_COPY_AND_ASSIGN(Win32ErrorLogMessage); +}; +#elif defined(OS_POSIX) +// Appends a formatted system message of the errno type +class ErrnoLogMessage { + public: + ErrnoLogMessage(const char* file, + int line, + LogSeverity severity, + SystemErrorCode err); + + std::ostream& stream() { return log_message_.stream(); } + + // Appends the error message before destructing the encapsulated class. + ~ErrnoLogMessage(); + + private: + SystemErrorCode err_; + LogMessage log_message_; + + DISALLOW_COPY_AND_ASSIGN(ErrnoLogMessage); +}; +#endif // OS_WIN + // Closes the log file explicitly if open. // NOTE: Since the log file is opened as necessary by the action of logging // statements, there's no guarantee that it will stay closed -- cgit v1.1