summaryrefslogtreecommitdiff
path: root/indra/llcommon/llerror.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/llerror.h')
-rw-r--r--indra/llcommon/llerror.h404
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