diff options
Diffstat (limited to 'indra/llcommon/llerror.h')
-rw-r--r-- | indra/llcommon/llerror.h | 404 |
1 files changed, 202 insertions, 202 deletions
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index d3d680ed33..84ac0fa7f0 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -1,8 +1,9 @@ /** * @file llerror.h - * @brief Constants, functions, and macros for logging and runtime errors. + * @date December 2006 + * @brief error message system * - * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc. * $License$ */ @@ -10,209 +11,208 @@ #define LL_LLERROR_H #include <sstream> -#include <stdio.h> -#include <stdarg.h> - -#include "llerrorstream.h" -#include "llerrorbuffer.h" - -// Specific error codes -const S32 LL_ERR_NOERR = 0; -const S32 LL_ERR_ASSET_REQUEST_FAILED = -1; -//const S32 LL_ERR_ASSET_REQUEST_INVALID = -2; -const S32 LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3; -const S32 LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4; -const S32 LL_ERR_INSUFFICIENT_PERMISSIONS = -5; -const S32 LL_ERR_EOF = -39; -const S32 LL_ERR_CANNOT_OPEN_FILE = -42; -const S32 LL_ERR_FILE_NOT_FOUND = -43; -const S32 LL_ERR_FILE_EMPTY = -44; -const S32 LL_ERR_TCP_TIMEOUT = -23016; -const S32 LL_ERR_CIRCUIT_GONE = -23017; - -// Error types - -#define LLERR_IMAGE (1 << 1) // Image requests -#define LLERR_MESSAGE (1 << 2) // Messaging -#define LLERR_PERF (1 << 3) // Performance -#define LLERR_SQL (1 << 4) // SQL statements -#define LLERR_DOUG (1 << 5) // Doug's debugging -#define LLERR_USER_INPUT (1 << 6) // Keyboard and mouse -#define LLERR_TIMING (1 << 7) // Verbose time info -#define LLERR_TASK (1 << 8) // Tracking tasks -#define LLERR_MSG_HANDLER (1 << 9) // -#define LLERR_CIRCUIT_INFO (1 << 10) // Message system circuit info -#define LLERR_PHYSICS (1 << 11) // physics -#define LLERR_VFS (1 << 12) // VFS -const U32 LLERR_ALL = 0xffff; -const U32 LLERR_NONE = 0x0; - -// Define one of these for different error levels in release... -// #define RELEASE_SHOW_DEBUG // Define this if you want your release builds to show lldebug output. -#define RELEASE_SHOW_INFO // Define this if you want your release builds to show llinfo output -#define RELEASE_SHOW_WARN // Define this if you want your release builds to show llwarn output. - - -////////////////////////////////////////// -// -// Implementation - ignore -// -// -#ifdef _DEBUG -#define SHOW_DEBUG -#define SHOW_WARN -#define SHOW_INFO -#define SHOW_ASSERT -#else // _DEBUG - -#ifdef RELEASE_SHOW_DEBUG -#define SHOW_DEBUG -#endif - -#ifdef RELEASE_SHOW_WARN -#define SHOW_WARN -#endif - -#ifdef RELEASE_SHOW_INFO -#define SHOW_INFO -#endif - -#ifdef RELEASE_SHOW_ASSERT -#define SHOW_ASSERT -#endif - -#endif // _DEBUG - - -extern LLErrorStream gErrorStream; - - -// LL Error macros -// -// Usage: -// -// llerrs << "An error, oh my!" << variable << endl; -// llwarns << "Another error, fuck me!" << variable << endl; -// llwarnst(LLERR_IMAGE) << "Debug, mother fucker" << endl; -// -// NOTE: The output format of filename(lineno): is so that MS DevStudio -// can parse the output and automatically jump to that location - -inline std::string llerrno_string(int errnum) +#include <typeinfo> + +#include "llerrorlegacy.h" + + +/* Error Logging Facility + + Information for most users: + + Code can log messages with constuctions like this: + + llinfos << "request to fizzbip agent " << agent_id + << " denied due to timeout" << llendl; + + Messages can be logged to one of four increasing levels of concern, + using one of four "streams": + + lldebugs - debug messages that are normally supressed + llinfos - informational messages that are normall shown + llwarns - warning messages that singal a problem + llerrs - error messages that are major, unrecoverable failures + + The later (llerrs) automatically crashes the process after the message + is logged. + + Note that these "streams" are actually #define magic. Rules for use: + * they cannot be used as normal streams, only to start a message + * messages written to them MUST be terminated with llendl + * between the opening and closing, the << operator is indeed + writing onto a std::ostream, so all conversions and stream + formating are available + + These messages are automatically logged with function name, and (if enabled) + file and line of the message. (Note: Existing messages that already include + the function name don't get name printed twice.) + + If you have a class, adding LOG_CLASS line to the declaration will cause + all messages emitted from member functions (normal and static) to be tagged + with the proper class name as well as the function name: + + class LLFoo + { + LOG_CLASS(LLFoo); + public: + ... + }; + + void LLFoo::doSomething(int i) + { + if (i > 100) + { + llwanrs << "called with a big value for i: " << i << llendl; + } + ... + } + + will result in messages like: + + WARN: LLFoo::doSomething: called with a big value for i: 283 + + Which messages are logged and which are supressed can be controled at run + time from the live file logcontrol.xml based on function, class and/or + source file. See etc/logcontrol-dev.xml for details. + + Lastly, logging is now very efficient in both compiled code and execution + when skipped. There is no need to wrap messages, even debugging ones, in + #ifdef _DEBUG constructs. lldebugs messages are compiled into all builds, + even release. Which means you can use them to help debug even when deployed + to a real grid. +*/ + +namespace LLError { - std::stringstream res; - res << "error(" << errnum << "):" << strerror(errnum) << " "; - return res.str(); + enum ELevel + { + LEVEL_ALL = 0, + // used to indicate that all messagess should be logged + + LEVEL_DEBUG = 0, + LEVEL_INFO = 1, + LEVEL_WARN = 2, + LEVEL_ERROR = 3, // used to be called FATAL + + LEVEL_NONE = 4 + // not really a level + // used to indicate that no messages should be logged + }; + + /* Macro support + The classes CallSite and Log are used by the logging macros below. + They are not intended for general use. + */ + + class CallSite; + + class Log + { + public: + static bool shouldLog(CallSite&); + static std::ostringstream* out(); + static void flush(std::ostringstream*, const CallSite&); + }; + + class CallSite + { + // Represents a specific place in the code where a message is logged + // This is public because it is used by the macros below. It is not + // intended for public use. + public: + CallSite(ELevel, const char* file, int line, + const std::type_info& class_info, const char* function); + + bool shouldLog() + { return mCached ? mShouldLog : Log::shouldLog(*this); } + // this member function needs to be in-line for efficiency + + void invalidate(); + + private: + // these describe the call site and never change + const ELevel mLevel; + const char* const mFile; + const int mLine; + const std::type_info& mClassInfo; + const char* const mFunction; + + // these implement a cache of the call to shouldLog() + bool mCached; + bool mShouldLog; + + friend class Log; + }; + + + class End { }; + inline std::ostream& operator<<(std::ostream& s, const End&) + { return s; } + // used to indicate the end of a message + + class NoClassInfo { }; + // used to indicate no class info known for logging } -inline std::string llerror_file_line(const char* file, S32 line) -{ - std::stringstream res; - res << file << "(" <<line << ")"; - return res.str(); -} -// Used to throw an error which is always causes a system halt. -#define llerrs if (gErrorStream.isEnabledFor(LLErrorBuffer::FATAL)) \ - { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::FATAL; \ - llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : error\n"; \ - llerror_oss << "ERROR: " << llerror_file_line(__FILE__, __LINE__) << " " - -// Used to show warnings -#define llwarns if (gErrorStream.isEnabledFor(LLErrorBuffer::WARN)) \ - { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::WARN; \ - if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : WARNING: "; \ - else llerror_oss << "WARNING: "; \ - llerror_oss - -// Alerts are for serious non-fatal situations that are not supposed to happen and need to alert someone -#define llalerts if (gErrorStream.isEnabledFor(LLErrorBuffer::WARN)) \ - { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::WARN; \ - if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : ALERT: "; \ - else llerror_oss << "ALERT: "; \ - llerror_oss - -// Used to show informational messages that don't get disabled -#define llinfos if (gErrorStream.isEnabledFor(LLErrorBuffer::INFO)) \ - { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::INFO; \ - if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : INFO: "; \ - else llerror_oss << "INFO: "; \ - llerror_oss - -#define llinfost(type) if (gErrorStream.isEnabledFor(LLErrorBuffer::INFO, type)) \ - { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::INFO; \ - if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : INFO: "; \ - else llerror_oss << "INFO: [" << #type << "] "; \ - llerror_oss - -// Used for general debugging output -#define lldebugs if (gErrorStream.isEnabledFor(LLErrorBuffer::DEBUG)) \ - { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::DEBUG; \ - if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : DEBUG: "; \ - else llerror_oss << "DEBUG: "; \ - llerror_oss - -#define lldebugst(type) if (gErrorStream.isEnabledFor(LLErrorBuffer::DEBUG, type)) \ - { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::DEBUG; \ - if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : DEBUG: "; \ - else llerror_oss << "DEBUG: [" << #type << "] "; \ - llerror_oss - -#define llendl std::endl; gErrorStream.crashOnError(llerror_oss, llerror_level); } -#define llendflush std::endl << std::flush; gErrorStream.crashOnError(llerror_oss, llerror_level); } -#define llcont llerror_oss - -#define llerror(msg, num) llerrs << "Error # " << num << ": " << msg << llendl; - -#define llwarning(msg, num) llwarns << "Warning # " << num << ": " << msg << llendl; - -#ifdef SHOW_ASSERT -#define llassert(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl; -#else -#define llassert(func) -#endif -#define llassert_always(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl; - -#ifdef SHOW_ASSERT -#define llverify(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl; -#else -#define llverify(func) (func); // get rid of warning C4189 -#endif - -// handy compile-time assert - enforce those template parameters! -#define cassert(expn) typedef char __C_ASSERT__[(expn)?1:-1] /* Flawfinder: ignore */ - -// Makes the app go down in flames, but on purpose! -void _llcrash_and_loop(); - -// Use as follows: -// llinfos << llformat("Test:%d (%.2f %.2f)", idx, x, y) << llendl; -// -// *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun) -// should perhaps be replaced with boost::format. -inline std::string llformat(const char *fmt, ...) -{ - char tstr[1024]; /* Flawfinder: ignore */ - va_list va; - va_start(va, fmt); -#if LL_WINDOWS - _vsnprintf(tstr, 1024, fmt, va); -#else - vsnprintf(tstr, 1024, fmt, va); /* Flawfinder: ignore */ -#endif - va_end(va); - return std::string(tstr); -} -// Helper class to temporarily change error level for the current scope. -class LLScopedErrorLevel -{ -public: - LLScopedErrorLevel(LLErrorBuffer::ELevel error_level); - ~LLScopedErrorLevel(); - -private: - LLErrorBuffer::ELevel mOrigErrorLevel; -}; - +/* + Class type information for logging + */ + +#define LOG_CLASS(s) typedef s _LL_CLASS_TO_LOG + // Declares class to tag logged messages with. + // See top of file for example of how to use this + +typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; + // Outside a class declartion, or in class without LOG_CLASS(), this + // typedef causes the messages to not be associated with any class. + + + + + +/* + Error Logging Macros + See top of file for common usage. +*/ + +#define lllog(level) \ + { \ + static LLError::CallSite _site( \ + level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__);\ + if (_site.shouldLog()) \ + { \ + std::ostringstream* _out = LLError::Log::out(); \ + (*_out) + +#define llendl \ + LLError::End(); \ + LLError::Log::flush(_out, _site); \ + } \ + } + +#define llinfos lllog(LLError::LEVEL_INFO) +#define lldebugs lllog(LLError::LEVEL_DEBUG) +#define llwarns lllog(LLError::LEVEL_WARN) +#define llerrs lllog(LLError::LEVEL_ERROR) + +#define llcont (*_out) + /* + Use this construct if you need to do computation in the middle of a + message: + + llinfos << "the agent " << agend_id; + switch (f) + { + case FOP_SHRUGS: llcont << "shrugs"; break; + case FOP_TAPS: llcont << "points at " << who; break; + case FOP_SAYS: llcont << "says " << message; break; + } + llcont << " for " << t << " seconds" << llendl; + + Such computation is done iff the message will be logged. + */ + + #endif // LL_LLERROR_H |