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          *    &nbsp;  size_t depth = NDC.getDepth();
224          *
225          *    &nbsp;  ... complex sequence of calls
226          *
227          *    &nbsp;  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