/indra/llcommon/llerror.h

https://bitbucket.org/lindenlab/viewer-beta/ · C Header · 300 lines · 112 code · 41 blank · 147 comment · 2 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. #ifndef LL_LLERROR_H
  28. #define LL_LLERROR_H
  29. #include <sstream>
  30. #include <typeinfo>
  31. #include "llerrorlegacy.h"
  32. #include "stdtypes.h"
  33. /* Error Logging Facility
  34. Information for most users:
  35. Code can log messages with constructions like this:
  36. LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id
  37. << " denied due to timeout" << LL_ENDL;
  38. Messages can be logged to one of four increasing levels of concern,
  39. using one of four "streams":
  40. LL_DEBUGS("StringTag") - debug messages that are normally suppressed
  41. LL_INFOS("StringTag") - informational messages that are normal shown
  42. LL_WARNS("StringTag") - warning messages that signal a problem
  43. LL_ERRS("StringTag") - error messages that are major, unrecoverable failures
  44. The later (LL_ERRS("StringTag")) automatically crashes the process after the message
  45. is logged.
  46. Note that these "streams" are actually #define magic. Rules for use:
  47. * they cannot be used as normal streams, only to start a message
  48. * messages written to them MUST be terminated with LL_ENDL
  49. * between the opening and closing, the << operator is indeed
  50. writing onto a std::ostream, so all conversions and stream
  51. formating are available
  52. These messages are automatically logged with function name, and (if enabled)
  53. file and line of the message. (Note: Existing messages that already include
  54. the function name don't get name printed twice.)
  55. If you have a class, adding LOG_CLASS line to the declaration will cause
  56. all messages emitted from member functions (normal and static) to be tagged
  57. with the proper class name as well as the function name:
  58. class LLFoo
  59. {
  60. LOG_CLASS(LLFoo);
  61. public:
  62. ...
  63. };
  64. void LLFoo::doSomething(int i)
  65. {
  66. if (i > 100)
  67. {
  68. LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL;
  69. }
  70. ...
  71. }
  72. will result in messages like:
  73. WARN: LLFoo::doSomething: called with a big value for i: 283
  74. Which messages are logged and which are suppressed can be controlled at run
  75. time from the live file logcontrol.xml based on function, class and/or
  76. source file. See etc/logcontrol-dev.xml for details.
  77. Lastly, logging is now very efficient in both compiled code and execution
  78. when skipped. There is no need to wrap messages, even debugging ones, in
  79. #ifdef _DEBUG constructs. LL_DEBUGS("StringTag") messages are compiled into all builds,
  80. even release. Which means you can use them to help debug even when deployed
  81. to a real grid.
  82. */
  83. namespace LLError
  84. {
  85. enum ELevel
  86. {
  87. LEVEL_ALL = 0,
  88. // used to indicate that all messages should be logged
  89. LEVEL_DEBUG = 0,
  90. LEVEL_INFO = 1,
  91. LEVEL_WARN = 2,
  92. LEVEL_ERROR = 3, // used to be called FATAL
  93. LEVEL_NONE = 4
  94. // not really a level
  95. // used to indicate that no messages should be logged
  96. };
  97. /* Macro support
  98. The classes CallSite and Log are used by the logging macros below.
  99. They are not intended for general use.
  100. */
  101. class CallSite;
  102. class LL_COMMON_API Log
  103. {
  104. public:
  105. static bool shouldLog(CallSite&);
  106. static std::ostringstream* out();
  107. static void flush(std::ostringstream* out, char* message) ;
  108. static void flush(std::ostringstream*, const CallSite&);
  109. };
  110. class LL_COMMON_API CallSite
  111. {
  112. // Represents a specific place in the code where a message is logged
  113. // This is public because it is used by the macros below. It is not
  114. // intended for public use.
  115. public:
  116. CallSite(ELevel, const char* file, int line,
  117. const std::type_info& class_info, const char* function, const char* broadTag, const char* narrowTag, bool printOnce);
  118. bool shouldLog()
  119. { return mCached ? mShouldLog : Log::shouldLog(*this); }
  120. // this member function needs to be in-line for efficiency
  121. void invalidate();
  122. private:
  123. // these describe the call site and never change
  124. const ELevel mLevel;
  125. const char* const mFile;
  126. const int mLine;
  127. const std::type_info& mClassInfo;
  128. const char* const mFunction;
  129. const char* const mBroadTag;
  130. const char* const mNarrowTag;
  131. const bool mPrintOnce;
  132. // these implement a cache of the call to shouldLog()
  133. bool mCached;
  134. bool mShouldLog;
  135. friend class Log;
  136. };
  137. class End { };
  138. inline std::ostream& operator<<(std::ostream& s, const End&)
  139. { return s; }
  140. // used to indicate the end of a message
  141. class LL_COMMON_API NoClassInfo { };
  142. // used to indicate no class info known for logging
  143. //LLCallStacks keeps track of call stacks and output the call stacks to log file
  144. //when LLAppViewer::handleViewerCrash() is triggered.
  145. //
  146. //Note: to be simple, efficient and necessary to keep track of correct call stacks,
  147. //LLCallStacks is designed not to be thread-safe.
  148. //so try not to use it in multiple parallel threads at same time.
  149. //Used in a single thread at a time is fine.
  150. class LL_COMMON_API LLCallStacks
  151. {
  152. private:
  153. static char** sBuffer ;
  154. static S32 sIndex ;
  155. public:
  156. static void push(const char* function, const int line) ;
  157. static std::ostringstream* insert(const char* function, const int line) ;
  158. static void print() ;
  159. static void clear() ;
  160. static void end(std::ostringstream* _out) ;
  161. };
  162. }
  163. //this is cheaper than llcallstacks if no need to output other variables to call stacks.
  164. #define llpushcallstacks LLError::LLCallStacks::push(__FUNCTION__, __LINE__)
  165. #define llcallstacks \
  166. {\
  167. std::ostringstream* _out = LLError::LLCallStacks::insert(__FUNCTION__, __LINE__) ; \
  168. (*_out)
  169. #define llcallstacksendl \
  170. LLError::End(); \
  171. LLError::LLCallStacks::end(_out) ; \
  172. }
  173. #define llclearcallstacks LLError::LLCallStacks::clear()
  174. #define llprintcallstacks LLError::LLCallStacks::print()
  175. /*
  176. Class type information for logging
  177. */
  178. #define LOG_CLASS(s) typedef s _LL_CLASS_TO_LOG
  179. // Declares class to tag logged messages with.
  180. // See top of file for example of how to use this
  181. typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
  182. // Outside a class declaration, or in class without LOG_CLASS(), this
  183. // typedef causes the messages to not be associated with any class.
  184. /*
  185. Error Logging Macros
  186. See top of file for common usage.
  187. */
  188. #define lllog(level, broadTag, narrowTag, once) \
  189. do { \
  190. static LLError::CallSite _site( \
  191. level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, broadTag, narrowTag, once);\
  192. if (LL_UNLIKELY(_site.shouldLog())) \
  193. { \
  194. std::ostringstream* _out = LLError::Log::out(); \
  195. (*_out)
  196. // DEPRECATED: Don't call directly, use LL_ENDL instead, which actually looks like a macro
  197. #define llendl \
  198. LLError::End(); \
  199. LLError::Log::flush(_out, _site); \
  200. } \
  201. } while(0)
  202. // DEPRECATED: Use the new macros that allow tags and *look* like macros.
  203. #define lldebugs lllog(LLError::LEVEL_DEBUG, NULL, NULL, false)
  204. #define llinfos lllog(LLError::LEVEL_INFO, NULL, NULL, false)
  205. #define llwarns lllog(LLError::LEVEL_WARN, NULL, NULL, false)
  206. #define llerrs lllog(LLError::LEVEL_ERROR, NULL, NULL, false)
  207. #define llcont (*_out)
  208. // NEW Macros for debugging, allow the passing of a string tag
  209. // One Tag
  210. #define LL_DEBUGS(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, false)
  211. #define LL_INFOS(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, false)
  212. #define LL_WARNS(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, false)
  213. #define LL_ERRS(broadTag) lllog(LLError::LEVEL_ERROR, broadTag, NULL, false)
  214. // Two Tags
  215. #define LL_DEBUGS2(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, false)
  216. #define LL_INFOS2(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, false)
  217. #define LL_WARNS2(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, false)
  218. #define LL_ERRS2(broadTag, narrowTag) lllog(LLError::LEVEL_ERROR, broadTag, narrowTag, false)
  219. // Only print the log message once (good for warnings or infos that would otherwise
  220. // spam the log file over and over, such as tighter loops).
  221. #define LL_DEBUGS_ONCE(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, true)
  222. #define LL_INFOS_ONCE(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, true)
  223. #define LL_WARNS_ONCE(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, true)
  224. #define LL_DEBUGS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, true)
  225. #define LL_INFOS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, true)
  226. #define LL_WARNS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, true)
  227. #define LL_ENDL llendl
  228. #define LL_CONT (*_out)
  229. /*
  230. Use this construct if you need to do computation in the middle of a
  231. message:
  232. LL_INFOS("AgentGesture") << "the agent " << agend_id;
  233. switch (f)
  234. {
  235. case FOP_SHRUGS: LL_CONT << "shrugs"; break;
  236. case FOP_TAPS: LL_CONT << "points at " << who; break;
  237. case FOP_SAYS: LL_CONT << "says " << message; break;
  238. }
  239. LL_CONT << " for " << t << " seconds" << LL_ENDL;
  240. Such computation is done iff the message will be logged.
  241. */
  242. #endif // LL_LLERROR_H