PageRenderTime 91ms CodeModel.GetById 61ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llcommon/llerror.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 300 lines | 112 code | 41 blank | 147 comment | 1 complexity | 4ac5e344878e454190d7c1e93b054c46 MD5 | raw file
  1/** 
  2 * @file llerror.h
  3 * @date   December 2006
  4 * @brief error message system
  5 *
  6 * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  7 * Second Life Viewer Source Code
  8 * Copyright (C) 2010, Linden Research, Inc.
  9 * 
 10 * This library is free software; you can redistribute it and/or
 11 * modify it under the terms of the GNU Lesser General Public
 12 * License as published by the Free Software Foundation;
 13 * version 2.1 of the License only.
 14 * 
 15 * This library is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 18 * Lesser General Public License for more details.
 19 * 
 20 * You should have received a copy of the GNU Lesser General Public
 21 * License along with this library; if not, write to the Free Software
 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 23 * 
 24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 25 * $/LicenseInfo$
 26 */
 27
 28#ifndef LL_LLERROR_H
 29#define LL_LLERROR_H
 30
 31#include <sstream>
 32#include <typeinfo>
 33
 34#include "llerrorlegacy.h"
 35#include "stdtypes.h"
 36
 37
 38/* Error Logging Facility
 39
 40	Information for most users:
 41	
 42	Code can log messages with constructions like this:
 43	
 44		LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id
 45			<< " denied due to timeout" << LL_ENDL;
 46		
 47	Messages can be logged to one of four increasing levels of concern,
 48	using one of four "streams":
 49
 50		LL_DEBUGS("StringTag")	- debug messages that are normally suppressed
 51		LL_INFOS("StringTag")	- informational messages that are normal shown
 52		LL_WARNS("StringTag")	- warning messages that signal a problem
 53		LL_ERRS("StringTag")	- error messages that are major, unrecoverable failures
 54		
 55	The later (LL_ERRS("StringTag")) automatically crashes the process after the message
 56	is logged.
 57	
 58	Note that these "streams" are actually #define magic.  Rules for use:
 59		* they cannot be used as normal streams, only to start a message
 60		* messages written to them MUST be terminated with LL_ENDL
 61		* between the opening and closing, the << operator is indeed
 62		  writing onto a std::ostream, so all conversions and stream
 63		  formating are available
 64	
 65	These messages are automatically logged with function name, and (if enabled)
 66	file and line of the message.  (Note: Existing messages that already include
 67	the function name don't get name printed twice.)
 68	
 69	If you have a class, adding LOG_CLASS line to the declaration will cause
 70	all messages emitted from member functions (normal and static) to be tagged
 71	with the proper class name as well as the function name:
 72	
 73		class LLFoo
 74		{
 75			LOG_CLASS(LLFoo);
 76		public:
 77			...
 78		};
 79	
 80		void LLFoo::doSomething(int i)
 81		{
 82			if (i > 100)
 83			{
 84				LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL; 
 85			}
 86			...
 87		}
 88	
 89	will result in messages like:
 90	
 91		WARN: LLFoo::doSomething: called with a big value for i: 283
 92	
 93	Which messages are logged and which are suppressed can be controlled at run
 94	time from the live file logcontrol.xml based on function, class and/or 
 95	source file.  See etc/logcontrol-dev.xml for details.
 96	
 97	Lastly, logging is now very efficient in both compiled code and execution
 98	when skipped.  There is no need to wrap messages, even debugging ones, in
 99	#ifdef _DEBUG constructs.  LL_DEBUGS("StringTag") messages are compiled into all builds,
100	even release.  Which means you can use them to help debug even when deployed
101	to a real grid.
102*/
103
104namespace LLError
105{
106	enum ELevel
107	{
108		LEVEL_ALL = 0,
109			// used to indicate that all messages 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 LL_COMMON_API Log
129	{
130	public:
131		static bool shouldLog(CallSite&);
132		static std::ostringstream* out();
133		static void flush(std::ostringstream* out, char* message)  ;
134		static void flush(std::ostringstream*, const CallSite&);
135	};
136	
137	class LL_COMMON_API CallSite
138	{
139		// Represents a specific place in the code where a message is logged
140		// This is public because it is used by the macros below.  It is not
141		// intended for public use.
142	public:
143		CallSite(ELevel, const char* file, int line,
144				const std::type_info& class_info, const char* function, const char* broadTag, const char* narrowTag, bool printOnce);
145						
146		bool shouldLog()
147			{ return mCached ? mShouldLog : Log::shouldLog(*this); }
148			// this member function needs to be in-line for efficiency
149		
150		void invalidate();
151		
152	private:
153		// these describe the call site and never change
154		const ELevel			mLevel;
155		const char* const		mFile;
156		const int			mLine;
157		const std::type_info&   	mClassInfo;
158		const char* const		mFunction;
159		const char* const		mBroadTag;
160		const char* const		mNarrowTag;
161		const bool			mPrintOnce;
162		
163		// these implement a cache of the call to shouldLog()
164		bool mCached;
165		bool mShouldLog;
166		
167		friend class Log;
168	};
169	
170	
171	class End { };
172	inline std::ostream& operator<<(std::ostream& s, const End&)
173		{ return s; }
174		// used to indicate the end of a message
175		
176	class LL_COMMON_API NoClassInfo { };
177		// used to indicate no class info known for logging
178
179   //LLCallStacks keeps track of call stacks and output the call stacks to log file
180   //when LLAppViewer::handleViewerCrash() is triggered.
181   //
182   //Note: to be simple, efficient and necessary to keep track of correct call stacks, 
183	//LLCallStacks is designed not to be thread-safe.
184   //so try not to use it in multiple parallel threads at same time.
185   //Used in a single thread at a time is fine.
186   class LL_COMMON_API LLCallStacks
187   {
188   private:
189       static char**  sBuffer ;
190	   static S32     sIndex ;
191          
192   public:   
193	   static void push(const char* function, const int line) ;
194	   static std::ostringstream* insert(const char* function, const int line) ;
195       static void print() ;
196       static void clear() ;
197	   static void end(std::ostringstream* _out) ;
198   }; 
199}
200
201//this is cheaper than llcallstacks if no need to output other variables to call stacks. 
202#define llpushcallstacks LLError::LLCallStacks::push(__FUNCTION__, __LINE__)
203#define llcallstacks \
204	{\
205       std::ostringstream* _out = LLError::LLCallStacks::insert(__FUNCTION__, __LINE__) ; \
206       (*_out)
207#define llcallstacksendl \
208		LLError::End(); \
209		LLError::LLCallStacks::end(_out) ; \
210	}
211#define llclearcallstacks LLError::LLCallStacks::clear()
212#define llprintcallstacks LLError::LLCallStacks::print() 
213
214/*
215	Class type information for logging
216 */
217
218#define LOG_CLASS(s)	typedef s _LL_CLASS_TO_LOG
219	// Declares class to tag logged messages with.
220	// See top of file for example of how to use this
221	
222typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
223	// Outside a class declaration, or in class without LOG_CLASS(), this
224	// typedef causes the messages to not be associated with any class.
225
226
227
228
229
230/*
231	Error Logging Macros
232	See top of file for common usage.	
233*/
234
235#define lllog(level, broadTag, narrowTag, once) \
236	do { \
237		static LLError::CallSite _site( \
238			level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, broadTag, narrowTag, once);\
239		if (LL_UNLIKELY(_site.shouldLog()))			\
240		{ \
241			std::ostringstream* _out = LLError::Log::out(); \
242			(*_out)
243
244// DEPRECATED: Don't call directly, use LL_ENDL instead, which actually looks like a macro
245#define llendl \
246			LLError::End(); \
247			LLError::Log::flush(_out, _site); \
248		} \
249	} while(0)
250
251// DEPRECATED: Use the new macros that allow tags and *look* like macros.
252#define lldebugs	lllog(LLError::LEVEL_DEBUG, NULL, NULL, false)
253#define llinfos		lllog(LLError::LEVEL_INFO, NULL, NULL, false)
254#define llwarns		lllog(LLError::LEVEL_WARN, NULL, NULL, false)
255#define llerrs		lllog(LLError::LEVEL_ERROR, NULL, NULL, false)
256#define llcont		(*_out)
257
258// NEW Macros for debugging, allow the passing of a string tag
259
260// One Tag
261#define LL_DEBUGS(broadTag)	lllog(LLError::LEVEL_DEBUG, broadTag, NULL, false)
262#define LL_INFOS(broadTag)	lllog(LLError::LEVEL_INFO, broadTag, NULL, false)
263#define LL_WARNS(broadTag)	lllog(LLError::LEVEL_WARN, broadTag, NULL, false)
264#define LL_ERRS(broadTag)	lllog(LLError::LEVEL_ERROR, broadTag, NULL, false)
265// Two Tags
266#define LL_DEBUGS2(broadTag, narrowTag)	lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, false)
267#define LL_INFOS2(broadTag, narrowTag)	lllog(LLError::LEVEL_INFO, broadTag, narrowTag, false)
268#define LL_WARNS2(broadTag, narrowTag)	lllog(LLError::LEVEL_WARN, broadTag, narrowTag, false)
269#define LL_ERRS2(broadTag, narrowTag)	lllog(LLError::LEVEL_ERROR, broadTag, narrowTag, false)
270
271// Only print the log message once (good for warnings or infos that would otherwise
272// spam the log file over and over, such as tighter loops).
273#define LL_DEBUGS_ONCE(broadTag)	lllog(LLError::LEVEL_DEBUG, broadTag, NULL, true)
274#define LL_INFOS_ONCE(broadTag)	lllog(LLError::LEVEL_INFO, broadTag, NULL, true)
275#define LL_WARNS_ONCE(broadTag)	lllog(LLError::LEVEL_WARN, broadTag, NULL, true)
276#define LL_DEBUGS2_ONCE(broadTag, narrowTag)	lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, true)
277#define LL_INFOS2_ONCE(broadTag, narrowTag)	lllog(LLError::LEVEL_INFO, broadTag, narrowTag, true)
278#define LL_WARNS2_ONCE(broadTag, narrowTag)	lllog(LLError::LEVEL_WARN, broadTag, narrowTag, true)
279
280#define LL_ENDL llendl
281#define LL_CONT	(*_out)
282
283	/*
284		Use this construct if you need to do computation in the middle of a
285		message:
286		
287			LL_INFOS("AgentGesture") << "the agent " << agend_id;
288			switch (f)
289			{
290				case FOP_SHRUGS:	LL_CONT << "shrugs";				break;
291				case FOP_TAPS:		LL_CONT << "points at " << who;	break;
292				case FOP_SAYS:		LL_CONT << "says " << message;	break;
293			}
294			LL_CONT << " for " << t << " seconds" << LL_ENDL;
295		
296		Such computation is done iff the message will be logged.
297	*/
298
299
300#endif // LL_LLERROR_H