llerror.h

Go to the documentation of this file.
00001 
00033 #ifndef LL_LLERROR_H
00034 #define LL_LLERROR_H
00035 
00036 #include <sstream>
00037 #include <typeinfo>
00038 
00039 #include "llerrorlegacy.h"
00040 
00041 
00042 /* Error Logging Facility
00043 
00044         Information for most users:
00045         
00046         Code can log messages with constuctions like this:
00047         
00048                 LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id
00049                         << " denied due to timeout" << LL_ENDL;
00050                 
00051         Messages can be logged to one of four increasing levels of concern,
00052         using one of four "streams":
00053 
00054                 LL_DEBUGS("StringTag")  - debug messages that are normally supressed
00055                 LL_INFOS("StringTag")   - informational messages that are normall shown
00056                 LL_WARNS("StringTag")   - warning messages that singal a problem
00057                 LL_ERRS("StringTag")    - error messages that are major, unrecoverable failures
00058                 
00059         The later (LL_ERRS("StringTag")) automatically crashes the process after the message
00060         is logged.
00061         
00062         Note that these "streams" are actually #define magic.  Rules for use:
00063                 * they cannot be used as normal streams, only to start a message
00064                 * messages written to them MUST be terminated with LL_ENDL
00065                 * between the opening and closing, the << operator is indeed
00066                   writing onto a std::ostream, so all conversions and stream
00067                   formating are available
00068         
00069         These messages are automatically logged with function name, and (if enabled)
00070         file and line of the message.  (Note: Existing messages that already include
00071         the function name don't get name printed twice.)
00072         
00073         If you have a class, adding LOG_CLASS line to the declaration will cause
00074         all messages emitted from member functions (normal and static) to be tagged
00075         with the proper class name as well as the function name:
00076         
00077                 class LLFoo
00078                 {
00079                         LOG_CLASS(LLFoo);
00080                 public:
00081                         ...
00082                 };
00083         
00084                 void LLFoo::doSomething(int i)
00085                 {
00086                         if (i > 100)
00087                         {
00088                                 LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL; 
00089                         }
00090                         ...
00091                 }
00092         
00093         will result in messages like:
00094         
00095                 WARN: LLFoo::doSomething: called with a big value for i: 283
00096         
00097         Which messages are logged and which are supressed can be controled at run
00098         time from the live file logcontrol.xml based on function, class and/or 
00099         source file.  See etc/logcontrol-dev.xml for details.
00100         
00101         Lastly, logging is now very efficient in both compiled code and execution
00102         when skipped.  There is no need to wrap messages, even debugging ones, in
00103         #ifdef _DEBUG constructs.  LL_DEBUGS("StringTag") messages are compiled into all builds,
00104         even release.  Which means you can use them to help debug even when deployed
00105         to a real grid.
00106 */
00107 
00108 namespace LLError
00109 {
00110         enum ELevel
00111         {
00112                 LEVEL_ALL = 0,
00113                         // used to indicate that all messagess should be logged
00114                         
00115                 LEVEL_DEBUG = 0,
00116                 LEVEL_INFO = 1,
00117                 LEVEL_WARN = 2,
00118                 LEVEL_ERROR = 3,        // used to be called FATAL
00119                 
00120                 LEVEL_NONE = 4
00121                         // not really a level
00122                         // used to indicate that no messages should be logged
00123         };
00124         
00125         /*      Macro support
00126                 The classes CallSite and Log are used by the logging macros below.
00127                 They are not intended for general use.
00128         */
00129         
00130         class CallSite;
00131         
00132         class Log
00133         {
00134         public:
00135                 static bool shouldLog(CallSite&);
00136                 static std::ostringstream* out();
00137                 static void flush(std::ostringstream*, const CallSite&);
00138         };
00139         
00140         class CallSite
00141         {
00142                 // Represents a specific place in the code where a message is logged
00143                 // This is public because it is used by the macros below.  It is not
00144                 // intended for public use.
00145         public:
00146                 CallSite(ELevel, const char* file, int line,
00147                                 const std::type_info& class_info, const char* function, const char* broadTag, const char* narrowTag, bool printOnce);
00148                                                 
00149                 bool shouldLog()
00150                         { return mCached ? mShouldLog : Log::shouldLog(*this); }
00151                         // this member function needs to be in-line for efficiency
00152                 
00153                 void invalidate();
00154                 
00155         private:
00156                 // these describe the call site and never change
00157                 const ELevel                    mLevel;
00158                 const char* const               mFile;
00159                 const int                       mLine;
00160                 const std::type_info&           mClassInfo;
00161                 const char* const               mFunction;
00162                 const char* const               mBroadTag;
00163                 const char* const               mNarrowTag;
00164                 const bool                      mPrintOnce;
00165                 
00166                 // these implement a cache of the call to shouldLog()
00167                 bool mCached;
00168                 bool mShouldLog;
00169                 
00170                 friend class Log;
00171         };
00172         
00173         
00174         class End { };
00175         inline std::ostream& operator<<(std::ostream& s, const End&)
00176                 { return s; }
00177                 // used to indicate the end of a message
00178                 
00179         class NoClassInfo { };
00180                 // used to indicate no class info known for logging
00181 }
00182 
00183 
00184 
00185 /*
00186         Class type information for logging
00187  */
00188 
00189 #define LOG_CLASS(s)    typedef s _LL_CLASS_TO_LOG
00190         // Declares class to tag logged messages with.
00191         // See top of file for example of how to use this
00192         
00193 typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
00194         // Outside a class declartion, or in class without LOG_CLASS(), this
00195         // typedef causes the messages to not be associated with any class.
00196 
00197 
00198 
00199 
00200 
00201 /*
00202         Error Logging Macros
00203         See top of file for common usage.       
00204 */
00205 
00206 #define lllog(level, broadTag, narrowTag, once) \
00207         { \
00208                 static LLError::CallSite _site( \
00209                         level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, broadTag, narrowTag, once);\
00210                 if (_site.shouldLog()) \
00211                 { \
00212                         std::ostringstream* _out = LLError::Log::out(); \
00213                         (*_out)
00214 
00215 // DEPRECATED: Don't call directly, use LL_ENDL instead, which actually looks like a macro
00216 #define llendl \
00217                         LLError::End(); \
00218                         LLError::Log::flush(_out, _site); \
00219                 } \
00220         }
00221 
00222 // DEPRECATED: Use the new macros that allow tags and *look* like macros.
00223 #define lldebugs        lllog(LLError::LEVEL_DEBUG, NULL, NULL, false)
00224 #define llinfos         lllog(LLError::LEVEL_INFO, NULL, NULL, false)
00225 #define llwarns         lllog(LLError::LEVEL_WARN, NULL, NULL, false)
00226 #define llerrs          lllog(LLError::LEVEL_ERROR, NULL, NULL, false)
00227 #define llcont          (*_out)
00228 
00229 // NEW Macros for debugging, allow the passing of a string tag
00230 
00231 // One Tag
00232 #define LL_DEBUGS(broadTag)     lllog(LLError::LEVEL_DEBUG, broadTag, NULL, false)
00233 #define LL_INFOS(broadTag)      lllog(LLError::LEVEL_INFO, broadTag, NULL, false)
00234 #define LL_WARNS(broadTag)      lllog(LLError::LEVEL_WARN, broadTag, NULL, false)
00235 #define LL_ERRS(broadTag)       lllog(LLError::LEVEL_ERROR, broadTag, NULL, false)
00236 // Two Tags
00237 #define LL_DEBUGS2(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, false)
00238 #define LL_INFOS2(broadTag, narrowTag)  lllog(LLError::LEVEL_INFO, broadTag, narrowTag, false)
00239 #define LL_WARNS2(broadTag, narrowTag)  lllog(LLError::LEVEL_WARN, broadTag, narrowTag, false)
00240 #define LL_ERRS2(broadTag, narrowTag)   lllog(LLError::LEVEL_ERROR, broadTag, narrowTag, false)
00241 
00242 // Only print the log message once (good for warnings or infos that would otherwise
00243 // spam the log file over and over, such as tighter loops).
00244 #define LL_DEBUGS_ONCE(broadTag)        lllog(LLError::LEVEL_DEBUG, broadTag, NULL, true)
00245 #define LL_INFOS_ONCE(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, true)
00246 #define LL_WARNS_ONCE(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, true)
00247 #define LL_DEBUGS2_ONCE(broadTag, narrowTag)    lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, true)
00248 #define LL_INFOS2_ONCE(broadTag, narrowTag)     lllog(LLError::LEVEL_INFO, broadTag, narrowTag, true)
00249 #define LL_WARNS2_ONCE(broadTag, narrowTag)     lllog(LLError::LEVEL_WARN, broadTag, narrowTag, true)
00250 
00251 #define LL_ENDL llendl
00252 #define LL_CONT (*_out)
00253 
00254         /*
00255                 Use this construct if you need to do computation in the middle of a
00256                 message:
00257                 
00258                         LL_INFOS("AgentGesture") << "the agent " << agend_id;
00259                         switch (f)
00260                         {
00261                                 case FOP_SHRUGS:        LL_CONT << "shrugs";                            break;
00262                                 case FOP_TAPS:          LL_CONT << "points at " << who; break;
00263                                 case FOP_SAYS:          LL_CONT << "says " << message;  break;
00264                         }
00265                         LL_CONT << " for " << t << " seconds" << LL_ENDL;
00266                 
00267                 Such computation is done iff the message will be logged.
00268         */
00269 
00270 
00271 #endif // LL_LLERROR_H

Generated on Fri May 16 08:32:02 2008 for SecondLife by  doxygen 1.5.5