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