You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							332 lines
						
					
					
						
							12 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							332 lines
						
					
					
						
							12 KiB
						
					
					
				| // -*- C++ -*- | |
| // Module:  Log4CPLUS | |
| // File:    ndc.h | |
| // Created: 6/2001 | |
| // Author:  Tad E. Smith | |
| // | |
| // | |
| // Copyright 2001-2010 Tad E. Smith | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| //     http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
|  | |
| /** @file  | |
|  * This header defined the NDC class. | |
|  */ | |
| 
 | |
| #ifndef _LO4CPLUS_NDC_HEADER_ | |
| #define _LO4CPLUS_NDC_HEADER_ | |
|  | |
| #include <log4cplus/config.hxx> | |
|  | |
| #if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE) | |
| #pragma once | |
| #endif | |
|  | |
| #include <log4cplus/tstring.h> | |
|  | |
| #include <map> | |
| #include <deque> | |
|  | |
| 
 | |
| namespace log4cplus { | |
|     // Forward declarations | |
|     struct DiagnosticContext; | |
|     typedef std::deque<DiagnosticContext> DiagnosticContextStack; | |
| 
 | |
|     /** | |
|      * The NDC class implements <i>nested diagnostic contexts</i> as | |
|      * defined by Neil Harrison in the article "Patterns for Logging | |
|      * Diagnostic Messages" part of the book "<i>Pattern Languages of | |
|      * Program Design 3</i>" edited by Martin et al. | |
|      * | |
|      * A Nested Diagnostic Context, or NDC in short, is an instrument | |
|      * to distinguish interleaved log output from different sources. Log | |
|      * output is typically interleaved when a server handles multiple | |
|      * clients near-simultaneously. | |
|      * | |
|      * Interleaved log output can still be meaningful if each log entry | |
|      * from different contexts had a distinctive stamp. This is where NDCs | |
|      * come into play. | |
|      * | |
|      * <em><b>Note that NDCs are managed on a per thread | |
|      * basis</b></em>. NDC operations such as {@link #push}, {@link | |
|      * #pop}, {@link #clear}, {@link #getDepth} and {@link #setMaxDepth} | |
|      * affect the NDC of the <em>current</em> thread only. NDCs of other | |
|      * threads remain unaffected. | |
|      * | |
|      * For example, a server can build a per client request NDC | |
|      * consisting the clients host name and other information contained in | |
|      * the the request. <em>Cookies</em> are another source of distinctive | |
|      * information. To build an NDC one uses the {@link #push} | |
|      * operation. Simply put, | |
|      * | |
|      * <ul> | |
|      *   <li>Contexts can be nested. | |
|      * | |
|      *   <li>When entering a context, call <code>getNDC().push()</code>. As a | |
|      *   side effect, if there is no nested diagnostic context for the | |
|      *   current thread, this method will create it. | |
|      * | |
|      *   <li>When leaving a context, call <code>getNDC().pop()</code>. | |
|      * | |
|      *   <li><b>When exiting a thread make sure to call {@link #remove | |
|      *   NDC.remove()}</b>.   | |
|      * </ul> | |
|      *                                           | |
|      * There is no penalty for forgetting to match each | |
|      * <code>push</code> operation with a corresponding <code>pop</code>, | |
|      * except the obvious mismatch between the real application context | |
|      * and the context set in the NDC.  Use of the {@link NDCContextCreator} | |
|      * class can automate this process and make your code exception-safe. | |
|      * | |
|      * If configured to do so, {@link log4cplus::PatternLayout} and | |
|      * {@link log4cplus::TTCCLayout} instances automatically retrieve | |
|      * the nested diagnostic context for the current thread without | |
|      * any user intervention.  Hence, even if a server is serving | |
|      * multiple clients simultaneously, the logs emanating from the | |
|      * same code (belonging to the same logger) can still be | |
|      * distinguished because each client request will have a different | |
|      * NDC tag. | |
|      * | |
|      * Heavy duty systems should call the {@link #remove} method when | |
|      * leaving the run method of a thread. This ensures that the memory | |
|      * used by the thread can be freed. | |
|      * | |
|      * A thread may inherit the nested diagnostic context of another | |
|      * (possibly parent) thread using the {@link #inherit inherit} | |
|      * method. A thread may obtain a copy of its NDC with the {@link | |
|      * #cloneStack cloneStack} method and pass the reference to any other | |
|      * thread, in particular to a child. | |
|      */ | |
|     class LOG4CPLUS_EXPORT NDC | |
|     { | |
|     public: | |
|         /** | |
|          * Clear any nested diagnostic information if any. This method is | |
|          * useful in cases where the same thread can be potentially used | |
|          * over and over in different unrelated contexts. | |
|          * | |
|          * This method is equivalent to calling the {@link #setMaxDepth} | |
|          * method with a zero <code>maxDepth</code> argument. | |
|          */ | |
|         void clear(); | |
| 
 | |
|         /** | |
|          * Clone the diagnostic context for the current thread. | |
|          * | |
|          * Internally a diagnostic context is represented as a stack.  A | |
|          * given thread can supply the stack (i.e. diagnostic context) to a | |
|          * child thread so that the child can inherit the parent thread's | |
|          * diagnostic context. | |
|          * | |
|          * The child thread uses the {@link #inherit inherit} method to | |
|          * inherit the parent's diagnostic context. | |
|          *                                         | |
|          * @return Stack A clone of the current thread's  diagnostic context. | |
|          */ | |
|         DiagnosticContextStack cloneStack() const; | |
| 
 | |
|         /** | |
|          * Inherit the diagnostic context of another thread. | |
|          * | |
|          * The parent thread can obtain a reference to its diagnostic | |
|          * context using the {@link #cloneStack} method.  It should | |
|          * communicate this information to its child so that it may inherit | |
|          * the parent's diagnostic context. | |
|          * | |
|          * The parent's diagnostic context is cloned before being | |
|          * inherited. In other words, once inherited, the two diagnostic | |
|          * contexts can be managed independently. | |
|          * | |
|          * @param stack The diagnostic context of the parent thread. | |
|          */ | |
|         void inherit(const DiagnosticContextStack& stack); | |
| 
 | |
|         /** | |
|          * Used when printing the diagnostic context. | |
|          */ | |
|         log4cplus::tstring const & get() const; | |
| 
 | |
|         /** | |
|          * Get the current nesting depth of this diagnostic context. | |
|          * | |
|          * @see #setMaxDepth | |
|          */ | |
|         std::size_t getDepth() const; | |
| 
 | |
|         /** | |
|          * Clients should call this method before leaving a diagnostic | |
|          * context. | |
|          * | |
|          * The returned value is the value that was pushed last. If no | |
|          * context is available, then the empty string "" is | |
|          * returned. If each call to push() is paired with a call to | |
|          * pop() (even in presence of thrown exceptions), the last | |
|          * pop() call frees the memory used by NDC for this | |
|          * thread. Otherwise, remove() must be called at the end of | |
|          * the thread to free the memory used by NDC for the thread. | |
|          * | |
|          * @return String The innermost diagnostic context. | |
|          * | |
|          * @see NDCContextCreator, remove(), push() | |
|          */ | |
|         log4cplus::tstring pop(); | |
| 
 | |
|         /** | |
|          * Same as pop() but without the return value. | |
|          */ | |
|         void pop_void (); | |
| 
 | |
|         /** | |
|          * Looks at the last diagnostic context at the top of this NDC | |
|          * without removing it. | |
|          * | |
|          * The returned value is the value that was pushed last. If no | |
|          * context is available, then the empty string "" is returned. | |
|          *                           | |
|          * @return String The innermost diagnostic context. | |
|          */ | |
|         log4cplus::tstring const & peek() const; | |
| 
 | |
|         /** | |
|          * Push new diagnostic context information for the current thread. | |
|          * | |
|          * The contents of the <code>message</code> parameter is | |
|          * determined solely by the client. Each call to push() should | |
|          * be paired with a call to pop(). | |
|          * | |
|          * @param message The new diagnostic context information. | |
|          * | |
|          * @see NDCContextCreator, pop(), remove() | |
|          */ | |
|         void push(const log4cplus::tstring& message); | |
|         void push(tchar const * message); | |
| 
 | |
|         /** | |
|          * Remove the diagnostic context for this thread. | |
|          * | |
|          * Each thread that created a diagnostic context by calling | |
|          * push() should call this method before exiting. Otherwise, | |
|          * the memory used by the thread cannot be reclaimed. It is | |
|          * possible to omit this call if and only if each push() call | |
|          * is always paired with a pop() call (even in presence of | |
|          * thrown exceptions). Then the memory used by NDC will be | |
|          * returned by the last pop() call and a call to remove() will | |
|          * be no-op. | |
|          */ | |
|         void remove(); | |
| 
 | |
|         /** | |
|          * Set maximum depth of this diagnostic context. If the current | |
|          * depth is smaller or equal to <code>maxDepth</code>, then no | |
|          * action is taken. | |
|          * | |
|          * This method is a convenient alternative to multiple {@link | |
|          * #pop} calls. Moreover, it is often the case that at the end of | |
|          * complex call sequences, the depth of the NDC is | |
|          * unpredictable. The <code>setMaxDepth</code> method circumvents | |
|          * this problem. | |
|          * | |
|          * For example, the combination | |
|          * <pre> | |
|          *    void foo() { | |
|          *       std::size_t depth = NDC.getDepth(); | |
|          * | |
|          *       ... complex sequence of calls | |
|          * | |
|          *       NDC.setMaxDepth(depth); | |
|          *    } | |
|          * </pre> | |
|          * | |
|          * ensures that between the entry and exit of foo the depth of the | |
|          * diagnostic stack is conserved. | |
|          *  | |
|          * <b>Note:</b>  Use of the {@link NDCContextCreator} class will solve | |
|          * this particular problem. | |
|          * | |
|          * @see #getDepth | |
|          */ | |
|         void setMaxDepth(std::size_t maxDepth); | |
| 
 | |
|         // Public ctor but only to be used by internal::DefaultContext. | |
|         NDC(); | |
| 
 | |
|       // Dtor | |
|         virtual ~NDC(); | |
| 
 | |
|     private: | |
|       // Methods | |
|         LOG4CPLUS_PRIVATE static DiagnosticContextStack* getPtr(); | |
| 
 | |
|         template <typename StringType> | |
|         LOG4CPLUS_PRIVATE | |
|         void push_worker (StringType const &); | |
| 
 | |
|       // Disallow construction (and copying) except by getNDC() | |
|         NDC(const NDC&); | |
|         NDC& operator=(const NDC&); | |
|     }; | |
| 
 | |
| 
 | |
|     /** | |
|      * Return a reference to the singleton object. | |
|      */ | |
|     LOG4CPLUS_EXPORT NDC& getNDC(); | |
| 
 | |
| 
 | |
|     /** | |
|      * This is the internal object that is stored on the NDC stack. | |
|      */ | |
|     struct LOG4CPLUS_EXPORT DiagnosticContext | |
|     { | |
|       // Ctors | |
|         DiagnosticContext(const log4cplus::tstring& message, | |
|             DiagnosticContext const * parent); | |
|         DiagnosticContext(tchar const * message, | |
|             DiagnosticContext const * parent); | |
|         DiagnosticContext(const log4cplus::tstring& message); | |
|         DiagnosticContext(tchar const * message); | |
|         DiagnosticContext(DiagnosticContext const &); | |
|         DiagnosticContext & operator = (DiagnosticContext const &); | |
| 
 | |
| #if defined (LOG4CPLUS_HAVE_RVALUE_REFS) | |
|         DiagnosticContext(DiagnosticContext &&); | |
|         DiagnosticContext & operator = (DiagnosticContext &&); | |
| #endif | |
|  | |
|         void swap (DiagnosticContext &); | |
| 
 | |
|       // Data | |
|         log4cplus::tstring message; /*!< The message at this context level. */ | |
|         log4cplus::tstring fullMessage; /*!< The entire message stack. */ | |
|     }; | |
| 
 | |
| 
 | |
|     /** | |
|      * This class ensures that a {@link NDC#push} call is always matched with | |
|      * a {@link NDC#pop} call even in the face of exceptions. | |
|      */ | |
|     class LOG4CPLUS_EXPORT NDCContextCreator { | |
|     public: | |
|         /** Pushes <code>msg</code> onto the NDC stack. */ | |
|         NDCContextCreator(const log4cplus::tstring& msg); | |
|         NDCContextCreator(tchar const * msg); | |
| 
 | |
|         /** Pops the NDC stack. */ | |
|         ~NDCContextCreator(); | |
|     }; | |
| 
 | |
| } // end namespace log4cplus | |
|  | |
| 
 | |
| #endif // _LO4CPLUS_NDC_HEADER_
 |