diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llcommon/llerror.h | 404 |
1 files changed, 202 insertions, 202 deletions
diff --git a/linden/indra/llcommon/llerror.h b/linden/indra/llcommon/llerror.h index 04e8eee..1285491 100644 --- a/linden/indra/llcommon/llerror.h +++ b/linden/indra/llcommon/llerror.h | |||
@@ -1,8 +1,9 @@ | |||
1 | /** | 1 | /** |
2 | * @file llerror.h | 2 | * @file llerror.h |
3 | * @brief Constants, functions, and macros for logging and runtime errors. | 3 | * @date December 2006 |
4 | * @brief error message system | ||
4 | * | 5 | * |
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | 6 | * Copyright (c) 2006-2007, Linden Research, Inc. |
6 | * | 7 | * |
7 | * The source code in this file ("Source Code") is provided by Linden Lab | 8 | * The source code in this file ("Source Code") is provided by Linden Lab |
8 | * to you under the terms of the GNU General Public License, version 2.0 | 9 | * to you under the terms of the GNU General Public License, version 2.0 |
@@ -29,209 +30,208 @@ | |||
29 | #define LL_LLERROR_H | 30 | #define LL_LLERROR_H |
30 | 31 | ||
31 | #include <sstream> | 32 | #include <sstream> |
32 | #include <stdio.h> | 33 | #include <typeinfo> |
33 | #include <stdarg.h> | 34 | |
34 | 35 | #include "llerrorlegacy.h" | |
35 | #include "llerrorstream.h" | 36 | |
36 | #include "llerrorbuffer.h" | 37 | |
37 | 38 | /* Error Logging Facility | |
38 | // Specific error codes | 39 | |
39 | const S32 LL_ERR_NOERR = 0; | 40 | Information for most users: |
40 | const S32 LL_ERR_ASSET_REQUEST_FAILED = -1; | 41 | |
41 | //const S32 LL_ERR_ASSET_REQUEST_INVALID = -2; | 42 | Code can log messages with constuctions like this: |
42 | const S32 LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3; | 43 | |
43 | const S32 LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4; | 44 | llinfos << "request to fizzbip agent " << agent_id |
44 | const S32 LL_ERR_INSUFFICIENT_PERMISSIONS = -5; | 45 | << " denied due to timeout" << llendl; |
45 | const S32 LL_ERR_EOF = -39; | 46 | |
46 | const S32 LL_ERR_CANNOT_OPEN_FILE = -42; | 47 | Messages can be logged to one of four increasing levels of concern, |
47 | const S32 LL_ERR_FILE_NOT_FOUND = -43; | 48 | using one of four "streams": |
48 | const S32 LL_ERR_FILE_EMPTY = -44; | 49 | |
49 | const S32 LL_ERR_TCP_TIMEOUT = -23016; | 50 | lldebugs - debug messages that are normally supressed |
50 | const S32 LL_ERR_CIRCUIT_GONE = -23017; | 51 | llinfos - informational messages that are normall shown |
51 | 52 | llwarns - warning messages that singal a problem | |
52 | // Error types | 53 | llerrs - error messages that are major, unrecoverable failures |
53 | 54 | ||
54 | #define LLERR_IMAGE (1 << 1) // Image requests | 55 | The later (llerrs) automatically crashes the process after the message |
55 | #define LLERR_MESSAGE (1 << 2) // Messaging | 56 | is logged. |
56 | #define LLERR_PERF (1 << 3) // Performance | 57 | |
57 | #define LLERR_SQL (1 << 4) // SQL statements | 58 | Note that these "streams" are actually #define magic. Rules for use: |
58 | #define LLERR_DOUG (1 << 5) // Doug's debugging | 59 | * they cannot be used as normal streams, only to start a message |
59 | #define LLERR_USER_INPUT (1 << 6) // Keyboard and mouse | 60 | * messages written to them MUST be terminated with llendl |
60 | #define LLERR_TIMING (1 << 7) // Verbose time info | 61 | * between the opening and closing, the << operator is indeed |
61 | #define LLERR_TASK (1 << 8) // Tracking tasks | 62 | writing onto a std::ostream, so all conversions and stream |
62 | #define LLERR_MSG_HANDLER (1 << 9) // | 63 | formating are available |
63 | #define LLERR_CIRCUIT_INFO (1 << 10) // Message system circuit info | 64 | |
64 | #define LLERR_PHYSICS (1 << 11) // physics | 65 | These messages are automatically logged with function name, and (if enabled) |
65 | #define LLERR_VFS (1 << 12) // VFS | 66 | file and line of the message. (Note: Existing messages that already include |
66 | const U32 LLERR_ALL = 0xffff; | 67 | the function name don't get name printed twice.) |
67 | const U32 LLERR_NONE = 0x0; | 68 | |
68 | 69 | If you have a class, adding LOG_CLASS line to the declaration will cause | |
69 | // Define one of these for different error levels in release... | 70 | all messages emitted from member functions (normal and static) to be tagged |
70 | // #define RELEASE_SHOW_DEBUG // Define this if you want your release builds to show lldebug output. | 71 | with the proper class name as well as the function name: |
71 | #define RELEASE_SHOW_INFO // Define this if you want your release builds to show llinfo output | 72 | |
72 | #define RELEASE_SHOW_WARN // Define this if you want your release builds to show llwarn output. | 73 | class LLFoo |
73 | 74 | { | |
74 | 75 | LOG_CLASS(LLFoo); | |
75 | ////////////////////////////////////////// | 76 | public: |
76 | // | 77 | ... |
77 | // Implementation - ignore | 78 | }; |
78 | // | 79 | |
79 | // | 80 | void LLFoo::doSomething(int i) |
80 | #ifdef _DEBUG | 81 | { |
81 | #define SHOW_DEBUG | 82 | if (i > 100) |
82 | #define SHOW_WARN | 83 | { |
83 | #define SHOW_INFO | 84 | llwanrs << "called with a big value for i: " << i << llendl; |
84 | #define SHOW_ASSERT | 85 | } |
85 | #else // _DEBUG | 86 | ... |
86 | 87 | } | |
87 | #ifdef RELEASE_SHOW_DEBUG | 88 | |
88 | #define SHOW_DEBUG | 89 | will result in messages like: |
89 | #endif | 90 | |
90 | 91 | WARN: LLFoo::doSomething: called with a big value for i: 283 | |
91 | #ifdef RELEASE_SHOW_WARN | 92 | |
92 | #define SHOW_WARN | 93 | Which messages are logged and which are supressed can be controled at run |
93 | #endif | 94 | time from the live file logcontrol.xml based on function, class and/or |
94 | 95 | source file. See etc/logcontrol-dev.xml for details. | |
95 | #ifdef RELEASE_SHOW_INFO | 96 | |
96 | #define SHOW_INFO | 97 | Lastly, logging is now very efficient in both compiled code and execution |
97 | #endif | 98 | when skipped. There is no need to wrap messages, even debugging ones, in |
98 | 99 | #ifdef _DEBUG constructs. lldebugs messages are compiled into all builds, | |
99 | #ifdef RELEASE_SHOW_ASSERT | 100 | even release. Which means you can use them to help debug even when deployed |
100 | #define SHOW_ASSERT | 101 | to a real grid. |
101 | #endif | 102 | */ |
102 | 103 | ||
103 | #endif // _DEBUG | 104 | namespace LLError |
104 | |||
105 | |||
106 | extern LLErrorStream gErrorStream; | ||
107 | |||
108 | |||
109 | // LL Error macros | ||
110 | // | ||
111 | // Usage: | ||
112 | // | ||
113 | // llerrs << "An error, oh my!" << variable << endl; | ||
114 | // llwarns << "Another error, fuck me!" << variable << endl; | ||
115 | // llwarnst(LLERR_IMAGE) << "Debug, mother fucker" << endl; | ||
116 | // | ||
117 | // NOTE: The output format of filename(lineno): is so that MS DevStudio | ||
118 | // can parse the output and automatically jump to that location | ||
119 | |||
120 | inline std::string llerrno_string(int errnum) | ||
121 | { | 105 | { |
122 | std::stringstream res; | 106 | enum ELevel |
123 | res << "error(" << errnum << "):" << strerror(errnum) << " "; | 107 | { |
124 | return res.str(); | 108 | LEVEL_ALL = 0, |
109 | // used to indicate that all messagess should be logged | ||
110 | |||
111 | LEVEL_DEBUG = 0, | ||
112 | LEVEL_INFO = 1, | ||
113 | LEVEL_WARN = 2, | ||
114 | LEVEL_ERROR = 3, // used to be called FATAL | ||
115 | |||
116 | LEVEL_NONE = 4 | ||
117 | // not really a level | ||
118 | // used to indicate that no messages should be logged | ||
119 | }; | ||
120 | |||
121 | /* Macro support | ||
122 | The classes CallSite and Log are used by the logging macros below. | ||
123 | They are not intended for general use. | ||
124 | */ | ||
125 | |||
126 | class CallSite; | ||
127 | |||
128 | class Log | ||
129 | { | ||
130 | public: | ||
131 | static bool shouldLog(CallSite&); | ||
132 | static std::ostringstream* out(); | ||
133 | static void flush(std::ostringstream*, const CallSite&); | ||
134 | }; | ||
135 | |||
136 | class CallSite | ||
137 | { | ||
138 | // Represents a specific place in the code where a message is logged | ||
139 | // This is public because it is used by the macros below. It is not | ||
140 | // intended for public use. | ||
141 | public: | ||
142 | CallSite(ELevel, const char* file, int line, | ||
143 | const std::type_info& class_info, const char* function); | ||
144 | |||
145 | bool shouldLog() | ||
146 | { return mCached ? mShouldLog : Log::shouldLog(*this); } | ||
147 | // this member function needs to be in-line for efficiency | ||
148 | |||
149 | void invalidate(); | ||
150 | |||
151 | private: | ||
152 | // these describe the call site and never change | ||
153 | const ELevel mLevel; | ||
154 | const char* const mFile; | ||
155 | const int mLine; | ||
156 | const std::type_info& mClassInfo; | ||
157 | const char* const mFunction; | ||
158 | |||
159 | // these implement a cache of the call to shouldLog() | ||
160 | bool mCached; | ||
161 | bool mShouldLog; | ||
162 | |||
163 | friend class Log; | ||
164 | }; | ||
165 | |||
166 | |||
167 | class End { }; | ||
168 | inline std::ostream& operator<<(std::ostream& s, const End&) | ||
169 | { return s; } | ||
170 | // used to indicate the end of a message | ||
171 | |||
172 | class NoClassInfo { }; | ||
173 | // used to indicate no class info known for logging | ||
125 | } | 174 | } |
126 | 175 | ||
127 | inline std::string llerror_file_line(const char* file, S32 line) | ||
128 | { | ||
129 | std::stringstream res; | ||
130 | res << file << "(" <<line << ")"; | ||
131 | return res.str(); | ||
132 | } | ||
133 | 176 | ||
134 | // Used to throw an error which is always causes a system halt. | ||
135 | #define llerrs if (gErrorStream.isEnabledFor(LLErrorBuffer::FATAL)) \ | ||
136 | { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::FATAL; \ | ||
137 | llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : error\n"; \ | ||
138 | llerror_oss << "ERROR: " << llerror_file_line(__FILE__, __LINE__) << " " | ||
139 | |||
140 | // Used to show warnings | ||
141 | #define llwarns if (gErrorStream.isEnabledFor(LLErrorBuffer::WARN)) \ | ||
142 | { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::WARN; \ | ||
143 | if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : WARNING: "; \ | ||
144 | else llerror_oss << "WARNING: "; \ | ||
145 | llerror_oss | ||
146 | |||
147 | // Alerts are for serious non-fatal situations that are not supposed to happen and need to alert someone | ||
148 | #define llalerts if (gErrorStream.isEnabledFor(LLErrorBuffer::WARN)) \ | ||
149 | { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::WARN; \ | ||
150 | if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : ALERT: "; \ | ||
151 | else llerror_oss << "ALERT: "; \ | ||
152 | llerror_oss | ||
153 | |||
154 | // Used to show informational messages that don't get disabled | ||
155 | #define llinfos if (gErrorStream.isEnabledFor(LLErrorBuffer::INFO)) \ | ||
156 | { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::INFO; \ | ||
157 | if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : INFO: "; \ | ||
158 | else llerror_oss << "INFO: "; \ | ||
159 | llerror_oss | ||
160 | |||
161 | #define llinfost(type) if (gErrorStream.isEnabledFor(LLErrorBuffer::INFO, type)) \ | ||
162 | { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::INFO; \ | ||
163 | if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : INFO: "; \ | ||
164 | else llerror_oss << "INFO: [" << #type << "] "; \ | ||
165 | llerror_oss | ||
166 | |||
167 | // Used for general debugging output | ||
168 | #define lldebugs if (gErrorStream.isEnabledFor(LLErrorBuffer::DEBUG)) \ | ||
169 | { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::DEBUG; \ | ||
170 | if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : DEBUG: "; \ | ||
171 | else llerror_oss << "DEBUG: "; \ | ||
172 | llerror_oss | ||
173 | |||
174 | #define lldebugst(type) if (gErrorStream.isEnabledFor(LLErrorBuffer::DEBUG, type)) \ | ||
175 | { std::ostringstream llerror_oss; LLErrorBuffer::ELevel llerror_level = LLErrorBuffer::DEBUG; \ | ||
176 | if (gErrorStream.getPrintLocation()) llerror_oss << llerror_file_line(__FILE__, __LINE__) << " : DEBUG: "; \ | ||
177 | else llerror_oss << "DEBUG: [" << #type << "] "; \ | ||
178 | llerror_oss | ||
179 | |||
180 | #define llendl std::endl; gErrorStream.crashOnError(llerror_oss, llerror_level); } | ||
181 | #define llendflush std::endl << std::flush; gErrorStream.crashOnError(llerror_oss, llerror_level); } | ||
182 | #define llcont llerror_oss | ||
183 | |||
184 | #define llerror(msg, num) llerrs << "Error # " << num << ": " << msg << llendl; | ||
185 | |||
186 | #define llwarning(msg, num) llwarns << "Warning # " << num << ": " << msg << llendl; | ||
187 | |||
188 | #ifdef SHOW_ASSERT | ||
189 | #define llassert(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl; | ||
190 | #else | ||
191 | #define llassert(func) | ||
192 | #endif | ||
193 | #define llassert_always(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl; | ||
194 | |||
195 | #ifdef SHOW_ASSERT | ||
196 | #define llverify(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl; | ||
197 | #else | ||
198 | #define llverify(func) (func); // get rid of warning C4189 | ||
199 | #endif | ||
200 | |||
201 | // handy compile-time assert - enforce those template parameters! | ||
202 | #define cassert(expn) typedef char __C_ASSERT__[(expn)?1:-1] | ||
203 | |||
204 | // Makes the app go down in flames, but on purpose! | ||
205 | void _llcrash_and_loop(); | ||
206 | |||
207 | // Use as follows: | ||
208 | // llinfos << llformat("Test:%d (%.2f %.2f)", idx, x, y) << llendl; | ||
209 | // | ||
210 | // *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun) | ||
211 | // should perhaps be replaced with boost::format. | ||
212 | inline std::string llformat(const char *fmt, ...) | ||
213 | { | ||
214 | char tstr[1024]; /* Flawfinder: ignore */ | ||
215 | va_list va; | ||
216 | va_start(va, fmt); | ||
217 | #if LL_WINDOWS | ||
218 | _vsnprintf(tstr, 1024, fmt, va); | ||
219 | #else | ||
220 | vsnprintf(tstr, 1024, fmt, va); /* Flawfinder: ignore */ | ||
221 | #endif | ||
222 | va_end(va); | ||
223 | return std::string(tstr); | ||
224 | } | ||
225 | 177 | ||
226 | // Helper class to temporarily change error level for the current scope. | 178 | /* |
227 | class LLScopedErrorLevel | 179 | Class type information for logging |
228 | { | 180 | */ |
229 | public: | 181 | |
230 | LLScopedErrorLevel(LLErrorBuffer::ELevel error_level); | 182 | #define LOG_CLASS(s) typedef s _LL_CLASS_TO_LOG |
231 | ~LLScopedErrorLevel(); | 183 | // Declares class to tag logged messages with. |
232 | 184 | // See top of file for example of how to use this | |
233 | private: | 185 | |
234 | LLErrorBuffer::ELevel mOrigErrorLevel; | 186 | typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; |
235 | }; | 187 | // Outside a class declartion, or in class without LOG_CLASS(), this |
236 | 188 | // typedef causes the messages to not be associated with any class. | |
189 | |||
190 | |||
191 | |||
192 | |||
193 | |||
194 | /* | ||
195 | Error Logging Macros | ||
196 | See top of file for common usage. | ||
197 | */ | ||
198 | |||
199 | #define lllog(level) \ | ||
200 | { \ | ||
201 | static LLError::CallSite _site( \ | ||
202 | level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__);\ | ||
203 | if (_site.shouldLog()) \ | ||
204 | { \ | ||
205 | std::ostringstream* _out = LLError::Log::out(); \ | ||
206 | (*_out) | ||
207 | |||
208 | #define llendl \ | ||
209 | LLError::End(); \ | ||
210 | LLError::Log::flush(_out, _site); \ | ||
211 | } \ | ||
212 | } | ||
213 | |||
214 | #define llinfos lllog(LLError::LEVEL_INFO) | ||
215 | #define lldebugs lllog(LLError::LEVEL_DEBUG) | ||
216 | #define llwarns lllog(LLError::LEVEL_WARN) | ||
217 | #define llerrs lllog(LLError::LEVEL_ERROR) | ||
218 | |||
219 | #define llcont (*_out) | ||
220 | /* | ||
221 | Use this construct if you need to do computation in the middle of a | ||
222 | message: | ||
223 | |||
224 | llinfos << "the agent " << agend_id; | ||
225 | switch (f) | ||
226 | { | ||
227 | case FOP_SHRUGS: llcont << "shrugs"; break; | ||
228 | case FOP_TAPS: llcont << "points at " << who; break; | ||
229 | case FOP_SAYS: llcont << "says " << message; break; | ||
230 | } | ||
231 | llcont << " for " << t << " seconds" << llendl; | ||
232 | |||
233 | Such computation is done iff the message will be logged. | ||
234 | */ | ||
235 | |||
236 | |||
237 | #endif // LL_LLERROR_H | 237 | #endif // LL_LLERROR_H |