ndc.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. // -*- C++ -*-
  2. // Module: Log4CPLUS
  3. // File: ndc.h
  4. // Created: 6/2001
  5. // Author: Tad E. Smith
  6. //
  7. //
  8. // Copyright 2001-2015 Tad E. Smith
  9. //
  10. // Licensed under the Apache License, Version 2.0 (the "License");
  11. // you may not use this file except in compliance with the License.
  12. // You may obtain a copy of the License at
  13. //
  14. // http://www.apache.org/licenses/LICENSE-2.0
  15. //
  16. // Unless required by applicable law or agreed to in writing, software
  17. // distributed under the License is distributed on an "AS IS" BASIS,
  18. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. // See the License for the specific language governing permissions and
  20. // limitations under the License.
  21. /** @file
  22. * This header defined the NDC class.
  23. */
  24. #ifndef _LO4CPLUS_NDC_HEADER_
  25. #define _LO4CPLUS_NDC_HEADER_
  26. #include <log4cplus/config.hxx>
  27. #if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE)
  28. #pragma once
  29. #endif
  30. #include <log4cplus/tstring.h>
  31. #include <map>
  32. #include <deque>
  33. namespace log4cplus {
  34. // Forward declarations
  35. struct DiagnosticContext;
  36. typedef std::deque<DiagnosticContext> DiagnosticContextStack;
  37. /**
  38. * The NDC class implements <i>nested diagnostic contexts</i> as
  39. * defined by Neil Harrison in the article "Patterns for Logging
  40. * Diagnostic Messages" part of the book <i>"Pattern Languages of
  41. * Program Design 3"</i> edited by Martin et al.
  42. *
  43. * A Nested Diagnostic Context, or NDC in short, is an instrument
  44. * to distinguish interleaved log output from different sources. Log
  45. * output is typically interleaved when a server handles multiple
  46. * clients near-simultaneously.
  47. *
  48. * Interleaved log output can still be meaningful if each log entry
  49. * from different contexts had a distinctive stamp. This is where NDCs
  50. * come into play.
  51. *
  52. * <em><b>Note that NDCs are managed on a per thread
  53. * basis</b></em>. NDC operations such as {@link #push}, {@link
  54. * #pop}, {@link #clear}, {@link #getDepth} and {@link #setMaxDepth}
  55. * affect the NDC of the <em>current</em> thread only. NDCs of other
  56. * threads remain unaffected.
  57. *
  58. * For example, a server can build a per client request NDC
  59. * consisting the clients host name and other information contained in
  60. * the the request. <em>Cookies</em> are another source of distinctive
  61. * information. To build an NDC one uses the {@link #push}
  62. * operation. Simply put,
  63. *
  64. * - Contexts can be nested.
  65. * - When entering a context, call `push()`. As a side effect, if
  66. * there is no nested diagnostic context for the current thread,
  67. * this method will create it.
  68. * - When leaving a context, call `pop()`.
  69. * - When exiting a thread make sure to call `remove()`.
  70. *
  71. * There is no penalty for forgetting to match each push()
  72. * operation with a corresponding pop(), except the obvious
  73. * mismatch between the real application context and the context
  74. * set in the NDC. Use of the NDCContextCreator class can
  75. * automate this process and make your code exception-safe.
  76. *
  77. * If configured to do so, {@link log4cplus::PatternLayout} and
  78. * {@link log4cplus::TTCCLayout} instances automatically retrieve
  79. * the nested diagnostic context for the current thread without
  80. * any user intervention. Hence, even if a server is serving
  81. * multiple clients simultaneously, the logs emanating from the
  82. * same code (belonging to the same logger) can still be
  83. * distinguished because each client request will have a different
  84. * NDC tag.
  85. *
  86. * Heavy duty systems should call the {@link #remove} method when
  87. * leaving the run method of a thread. This ensures that the memory
  88. * used by the thread can be freed.
  89. *
  90. * A thread may inherit the nested diagnostic context of another
  91. * (possibly parent) thread using the {@link #inherit inherit}
  92. * method. A thread may obtain a copy of its NDC with the {@link
  93. * #cloneStack cloneStack} method and pass the reference to any other
  94. * thread, in particular to a child.
  95. */
  96. class LOG4CPLUS_EXPORT NDC
  97. {
  98. public:
  99. /**
  100. * Clear any nested diagnostic information if any. This method is
  101. * useful in cases where the same thread can be potentially used
  102. * over and over in different unrelated contexts.
  103. *
  104. * This method is equivalent to calling the {@link #setMaxDepth}
  105. * method with a zero <code>maxDepth</code> argument.
  106. */
  107. void clear();
  108. /**
  109. * Clone the diagnostic context for the current thread.
  110. *
  111. * Internally a diagnostic context is represented as a stack. A
  112. * given thread can supply the stack (i.e. diagnostic context) to a
  113. * child thread so that the child can inherit the parent thread's
  114. * diagnostic context.
  115. *
  116. * The child thread uses the {@link #inherit inherit} method to
  117. * inherit the parent's diagnostic context.
  118. *
  119. * @return Stack A clone of the current thread's diagnostic context.
  120. */
  121. DiagnosticContextStack cloneStack() const;
  122. /**
  123. * Inherit the diagnostic context of another thread.
  124. *
  125. * The parent thread can obtain a reference to its diagnostic
  126. * context using the {@link #cloneStack} method. It should
  127. * communicate this information to its child so that it may inherit
  128. * the parent's diagnostic context.
  129. *
  130. * The parent's diagnostic context is cloned before being
  131. * inherited. In other words, once inherited, the two diagnostic
  132. * contexts can be managed independently.
  133. *
  134. * @param stack The diagnostic context of the parent thread.
  135. */
  136. void inherit(const DiagnosticContextStack& stack);
  137. /**
  138. * Used when printing the diagnostic context.
  139. */
  140. log4cplus::tstring const & get() const;
  141. /**
  142. * Get the current nesting depth of this diagnostic context.
  143. *
  144. * @see #setMaxDepth
  145. */
  146. std::size_t getDepth() const;
  147. /**
  148. * Clients should call this method before leaving a diagnostic
  149. * context.
  150. *
  151. * The returned value is the value that was pushed last. If no
  152. * context is available, then the empty string is returned. If
  153. * each call to `push()` is paired with a call to `pop()`
  154. * (even in presence of thrown exceptions), the last `pop()`
  155. * call frees the memory used by NDC for this
  156. * thread. Otherwise, `remove()` must be called at the end of
  157. * the thread to free the memory used by NDC for the thread.
  158. *
  159. * @return String The innermost diagnostic context.
  160. *
  161. * @see NDCContextCreator, remove(), push()
  162. */
  163. log4cplus::tstring pop();
  164. /**
  165. * Same as pop() but without the return value.
  166. */
  167. void pop_void ();
  168. /**
  169. * Looks at the last diagnostic context at the top of this NDC
  170. * without removing it.
  171. *
  172. * The returned value is the value that was pushed last. If no
  173. * context is available, then the empty string is returned.
  174. *
  175. * @return String The innermost diagnostic context.
  176. */
  177. log4cplus::tstring const & peek() const;
  178. /**
  179. * Push new diagnostic context information for the current thread.
  180. *
  181. * The contents of the <code>message</code> parameter is
  182. * determined solely by the client. Each call to push() should
  183. * be paired with a call to pop().
  184. *
  185. * @param message The new diagnostic context information.
  186. *
  187. * @see NDCContextCreator, pop(), remove()
  188. */
  189. void push(const log4cplus::tstring& message);
  190. void push(tchar const * message);
  191. /**
  192. * Remove the diagnostic context for this thread.
  193. *
  194. * Each thread that created a diagnostic context by calling
  195. * push() should call this method before exiting. Otherwise,
  196. * the memory used by the thread cannot be reclaimed. It is
  197. * possible to omit this call if and only if each push() call
  198. * is always paired with a pop() call (even in presence of
  199. * thrown exceptions). Then the memory used by NDC will be
  200. * returned by the last pop() call and a call to remove() will
  201. * be no-op.
  202. */
  203. void remove();
  204. /**
  205. * Set maximum depth of this diagnostic context. If the
  206. * current depth is smaller or equal to `maxDepth`, then no
  207. * action is taken.
  208. *
  209. * This method is a convenient alternative to multiple `pop()`
  210. * calls. Moreover, it is often the case that at the end of
  211. * complex call sequences, the depth of the NDC is
  212. * unpredictable. The `setMaxDepth()` method circumvents this
  213. * problem.
  214. *
  215. * For example, the combination
  216. *
  217. * ~~~~{.c}
  218. * void foo() {
  219. * NDC & ndc = getNDC();
  220. * std::size_t depth = ndc.getDepth();
  221. * //... complex sequence of calls
  222. * ndc.setMaxDepth(depth);
  223. * }
  224. * ~~~~
  225. *
  226. * ensures that between the entry and exit of foo the depth of the
  227. * diagnostic stack is conserved.
  228. *
  229. * \note Use of the NDCContextCreator class will solve this
  230. * particular problem.
  231. *
  232. * \see NDC::getDepth()
  233. */
  234. void setMaxDepth(std::size_t maxDepth);
  235. // Public ctor but only to be used by internal::DefaultContext.
  236. NDC();
  237. // Dtor
  238. virtual ~NDC();
  239. private:
  240. // Methods
  241. LOG4CPLUS_PRIVATE static DiagnosticContextStack* getPtr();
  242. template <typename StringType>
  243. LOG4CPLUS_PRIVATE
  244. void push_worker (StringType const &);
  245. // Disallow construction (and copying) except by getNDC()
  246. NDC(const NDC&);
  247. NDC& operator=(const NDC&);
  248. };
  249. /**
  250. * Return a reference to the singleton object.
  251. */
  252. LOG4CPLUS_EXPORT NDC& getNDC();
  253. /**
  254. * This is the internal object that is stored on the NDC stack.
  255. */
  256. struct LOG4CPLUS_EXPORT DiagnosticContext
  257. {
  258. // Ctors
  259. DiagnosticContext(const log4cplus::tstring& message,
  260. DiagnosticContext const * parent);
  261. DiagnosticContext(tchar const * message,
  262. DiagnosticContext const * parent);
  263. DiagnosticContext(const log4cplus::tstring& message);
  264. DiagnosticContext(tchar const * message);
  265. DiagnosticContext(DiagnosticContext const &);
  266. DiagnosticContext & operator = (DiagnosticContext const &);
  267. #if defined (LOG4CPLUS_HAVE_RVALUE_REFS)
  268. DiagnosticContext(DiagnosticContext &&);
  269. DiagnosticContext & operator = (DiagnosticContext &&);
  270. #endif
  271. void swap (DiagnosticContext &);
  272. // Data
  273. log4cplus::tstring message; /*!< The message at this context level. */
  274. log4cplus::tstring fullMessage; /*!< The entire message stack. */
  275. };
  276. /**
  277. * This class ensures that a `NDC::push()` call is always matched
  278. * with a `NDC::pop()` call even in the face of exceptions.
  279. */
  280. class LOG4CPLUS_EXPORT NDCContextCreator {
  281. public:
  282. /** Pushes <code>msg</code> onto the NDC stack. */
  283. NDCContextCreator(const log4cplus::tstring& msg);
  284. NDCContextCreator(tchar const * msg);
  285. /** Pops the NDC stack. */
  286. ~NDCContextCreator();
  287. };
  288. } // end namespace log4cplus
  289. #endif // _LO4CPLUS_NDC_HEADER_