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