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                 llinfos << "request to fizzbip agent " << agent_id
00049                         << " denied due to timeout" << llendl;
00050                 
00051         Messages can be logged to one of four increasing levels of concern,
00052         using one of four "streams":
00053 
00054                 lldebugs        - debug messages that are normally supressed
00055                 llinfos         - informational messages that are normall shown
00056                 llwarns         - warning messages that singal a problem
00057                 llerrs          - error messages that are major, unrecoverable failures
00058                 
00059         The later (llerrs) 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 llendl
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                                 llwanrs << "called with a big value for i: " << i << llendl; 
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.  lldebugs 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);
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                 
00163                 // these implement a cache of the call to shouldLog()
00164                 bool mCached;
00165                 bool mShouldLog;
00166                 
00167                 friend class Log;
00168         };
00169         
00170         
00171         class End { };
00172         inline std::ostream& operator<<(std::ostream& s, const End&)
00173                 { return s; }
00174                 // used to indicate the end of a message
00175                 
00176         class NoClassInfo { };
00177                 // used to indicate no class info known for logging
00178 }
00179 
00180 
00181 
00182 /*
00183         Class type information for logging
00184  */
00185 
00186 #define LOG_CLASS(s)    typedef s _LL_CLASS_TO_LOG
00187         // Declares class to tag logged messages with.
00188         // See top of file for example of how to use this
00189         
00190 typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
00191         // Outside a class declartion, or in class without LOG_CLASS(), this
00192         // typedef causes the messages to not be associated with any class.
00193 
00194 
00195 
00196 
00197 
00198 /*
00199         Error Logging Macros
00200         See top of file for common usage.       
00201 */
00202 
00203 #define lllog(level) \
00204         { \
00205                 static LLError::CallSite _site( \
00206                         level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__);\
00207                 if (_site.shouldLog()) \
00208                 { \
00209                         std::ostringstream* _out = LLError::Log::out(); \
00210                         (*_out)
00211         
00212 #define llendl \
00213                         LLError::End(); \
00214                         LLError::Log::flush(_out, _site); \
00215                 } \
00216         }
00217 
00218 #define llinfos         lllog(LLError::LEVEL_INFO)
00219 #define lldebugs        lllog(LLError::LEVEL_DEBUG)
00220 #define llwarns         lllog(LLError::LEVEL_WARN)
00221 #define llerrs          lllog(LLError::LEVEL_ERROR)
00222 
00223 #define llcont          (*_out)
00224         /*
00225                 Use this construct if you need to do computation in the middle of a
00226                 message:
00227                 
00228                         llinfos << "the agent " << agend_id;
00229                         switch (f)
00230                         {
00231                                 case FOP_SHRUGS:        llcont << "shrugs";                             break;
00232                                 case FOP_TAPS:          llcont << "points at " << who;  break;
00233                                 case FOP_SAYS:          llcont << "says " << message;   break;
00234                         }
00235                         llcont << " for " << t << " seconds" << llendl;
00236                 
00237                 Such computation is done iff the message will be logged.
00238         */
00239 
00240 
00241 #endif // LL_LLERROR_H

Generated on Thu Jul 1 06:08:29 2010 for Second Life Viewer by  doxygen 1.4.7