You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by sw...@apache.org on 2023/06/28 02:15:54 UTC

[logging-log4cxx] branch master updated: Improve the NDC documentation and remove Java specific statements (#221)

This is an automated email from the ASF dual-hosted git repository.

swebb2066 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git


The following commit(s) were added to refs/heads/master by this push:
     new 7d1a456b Improve the NDC documentation and remove Java specific statements (#221)
7d1a456b is described below

commit 7d1a456b5daae3c113b1ac0eaaf2b2abbdf7d92a
Author: Stephen Webb <st...@ieee.org>
AuthorDate: Wed Jun 28 12:15:49 2023 +1000

    Improve the NDC documentation and remove Java specific statements (#221)
---
 src/main/include/log4cxx/mdc.h                  |  88 ++++-----
 src/main/include/log4cxx/ndc.h                  | 245 ++++++++++--------------
 src/site/markdown/1-usage.md                    |   1 +
 src/site/markdown/nested-diagnostic-contexts.md |  69 +++++++
 src/site/markdown/usage.md                      |  49 -----
 5 files changed, 214 insertions(+), 238 deletions(-)

diff --git a/src/main/include/log4cxx/mdc.h b/src/main/include/log4cxx/mdc.h
index 01d44d55..a73c609a 100644
--- a/src/main/include/log4cxx/mdc.h
+++ b/src/main/include/log4cxx/mdc.h
@@ -26,12 +26,21 @@ namespace log4cxx
 {
 
 /**
-The MDC class is similar to the {@link log4cxx::NDC NDC} class except that it is
-based on a map instead of a stack. It provides <em>mapped
-diagnostic contexts</em>. A <em>Mapped Diagnostic Context</em>, or
+A <em>Mapped Diagnostic Context</em>, or
 MDC in short, is an instrument for distinguishing interleaved log
 output from different sources. Log output is typically interleaved
 when a server handles multiple clients near-simultaneously.
+
+#MDC provides a constructor and destructor which simply call the #put and
+#remove methods, allowing for automatic cleanup when the current scope ends.
+
+#MDC operations such as #put, #remove and #clear
+affect only logging events emitted in the <em>calling</em> thread.
+The contexts of other threads are not changed.
+That is, <em><b>contexts are managed on a per thread basis</b></em>.
+
+The MDC class is similar to the {@link log4cxx::NDC NDC} class except that it is
+based on a map instead of a stack.
 */
 class LOG4CXX_EXPORT MDC
 {
@@ -44,27 +53,23 @@ class LOG4CXX_EXPORT MDC
 		 *  Places a key/value pair in the MDC for the current thread
 		 *    which will be removed during the corresponding destructor.  Both
 		 *    construction and destruction are expected to be on the same thread.
-		 *    @param key key
-		 *    @param value value.
+		 *    @param key context identifier
+		 *    @param value a string that distinguishes this context.
 		 */
 		MDC(const std::string& key, const std::string& value);
 		~MDC();
 
 		/**
-		* Put a context value (the <code>o</code> parameter) as identified
-		* with the <code>key</code> parameter into the current thread's
-		* context map.
+		* Set the <code>key</code> context in the current thread's context map to <code>value</code>.
 		*
 		* <p>If the current thread does not have a context map it is
 		* created as a side effect.
-		 *    @param key key
-		 *    @param value value.
+		 *    @param key context identifier
+		 *    @param value a string that distinguishes this context.
 		*/
 		static void put(const std::string& key, const std::string& value);
 		/**
-		* Put a context value (the <code>o</code> parameter) as identified
-		* with the <code>key</code> parameter into the current thread's
-		* context map.
+		* Set the <code>key</code> context in the current thread's context map to <code>value</code>.
 		*
 		* <p>If the current thread does not have a context map it is
 		* created as a side effect.
@@ -75,7 +80,7 @@ class LOG4CXX_EXPORT MDC
 		* Get the context identified by the <code>key</code> parameter.
 		*
 		*  <p>This method has no side effects.
-		*  @param key key.
+		*  @param key context identifier.
 		*  @return value for key, empty if not set.
 		* */
 		static std::string get(const std::string& key);
@@ -90,7 +95,7 @@ class LOG4CXX_EXPORT MDC
 		/**
 		* Remove the the context identified by the <code>key</code>
 		* parameter.
-		*  @param key key.
+		*  @param key context identifier.
 		* @return value if key had been set, empty if not.
 		*/
 		static std::string remove(const std::string& key);
@@ -99,33 +104,31 @@ class LOG4CXX_EXPORT MDC
 		 *  Places a key/value pair in the MDC for the current thread
 		 *    which will be removed during the corresponding destructor.  Both
 		 *    construction and destruction are expected to be on the same thread.
-		 *    @param key key
-		 *    @param value value.
+		 *    @param key context identifier
+		 *    @param value a string that distinguishes this context.
 		 */
 		MDC(const std::wstring& key, const std::wstring& value);
 		/**
-		* Put a context value (the <code>o</code> parameter) as identified
-		* with the <code>key</code> parameter into the current thread's
-		* context map.
+		*  Set the <code>key</code> context in the current thread's context map to <code>value</code>.
 		*
 		* <p>If the current thread does not have a context map it is
 		* created as a side effect.
-		 *    @param key key
-		 *    @param value value.
+		 *    @param key context identifier
+		 *    @param value a string that distinguishes this context.
 		*/
 		static void put(const std::wstring& key, const std::wstring& value);
 		/**
 		* Get the context identified by the <code>key</code> parameter.
 		*
 		*  <p>This method has no side effects.
-		*  @param key key.
+		*  @param key context identifier.
 		*  @return value for key, empty if not set.
 		* */
 		static std::wstring get(const std::wstring& key);
 		/**
 		* Remove the the context identified by the <code>key</code>
 		* parameter.
-		*  @param key key.
+		*  @param key context identifier.
 		* @return value if key had been set, empty if not.
 		*/
 		static std::wstring remove(const std::wstring& key);
@@ -135,33 +138,31 @@ class LOG4CXX_EXPORT MDC
 		 *  Places a key/value pair in the MDC for the current thread
 		 *    which will be removed during the corresponding destructor.  Both
 		 *    construction and destruction are expected to be on the same thread.
-		 *    @param key key
-		 *    @param value value.
+		 *    @param key context identifier
+		 *    @param value a string that distinguishes this context.
 		 */
 		MDC(const std::basic_string<UniChar>& key, const std::basic_string<UniChar>& value);
 		/**
-		* Put a context value (the <code>o</code> parameter) as identified
-		* with the <code>key</code> parameter into the current thread's
-		* context map.
+		*  Set the <code>key</code> context in the current thread's context map to <code>value</code>.
 		*
 		* <p>If the current thread does not have a context map it is
 		* created as a side effect.
-		 *    @param key key
-		 *    @param value value.
+		 *    @param key context identifier
+		 *    @param value the value.
 		*/
 		static void put(const std::basic_string<UniChar>& key, const std::basic_string<UniChar>& value);
 		/**
 		* Get the context identified by the <code>key</code> parameter.
 		*
 		*  <p>This method has no side effects.
-		*  @param key key.
+		*  @param key context identifier.
 		*  @return value for key, empty if not set.
 		* */
 		static std::basic_string<UniChar> get(const std::basic_string<UniChar>& key);
 		/**
 		* Remove the the context identified by the <code>key</code>
 		* parameter.
-		*  @param key key.
+		*  @param key context identifier.
 		* @return value if key had been set, empty if not.
 		*/
 		static std::basic_string<UniChar> remove(const std::basic_string<UniChar>& key);
@@ -171,33 +172,31 @@ class LOG4CXX_EXPORT MDC
 		 *  Places a key/value pair in the MDC for the current thread
 		 *    which will be removed during the corresponding destructor.  Both
 		 *    construction and destruction are expected to be on the same thread.
-		 *    @param key key
-		 *    @param value value.
+		 *    @param key context identifier
+		 *    @param value a string that distinguishes this context.
 		 */
 		MDC(const CFStringRef& key, const CFStringRef& value);
 		/**
-		* Put a context value (the <code>o</code> parameter) as identified
-		* with the <code>key</code> parameter into the current thread's
-		* context map.
+		*  Set the <code>key</code> context in the current thread's context map to <code>value</code>.
 		*
 		* <p>If the current thread does not have a context map it is
 		* created as a side effect.
-		 *    @param key key
-		 *    @param value value.
+		 *    @param key context identifier
+		 *    @param value a string that distinguishes this context.
 		*/
 		static void put(const CFStringRef& key, const CFStringRef& value);
 		/**
 		* Get the context identified by the <code>key</code> parameter.
 		*
 		*  <p>This method has no side effects.
-		*  @param key key.
+		*  @param key context identifier.
 		*  @return value for key, empty if not set.
 		* */
 		static CFStringRef get(const CFStringRef& key);
 		/**
 		* Remove the the context identified by the <code>key</code>
 		* parameter.
-		*  @param key key.
+		*  @param key context identifier.
 		* @return value if key had been set, empty if not.
 		*/
 		static CFStringRef remove(const CFStringRef& key);
@@ -205,7 +204,7 @@ class LOG4CXX_EXPORT MDC
 		/**
 		* Remove the the context identified by the <code>key</code>
 		* parameter.
-		*  @param key key.
+		*  @param key context identifier.
 		* @param prevValue buffer to which previous value is appended.
 		* @return true if key existed in MDC.
 		*/
@@ -213,6 +212,9 @@ class LOG4CXX_EXPORT MDC
 
 		/**
 		* Clear all entries in the MDC.
+		* <p>A thread that adds to the diagnostic context by calling
+		* #put should call this method before exiting
+		* to prevent unbounded memory usage.
 		*/
 		static void clear();
 
diff --git a/src/main/include/log4cxx/ndc.h b/src/main/include/log4cxx/ndc.h
index c2642cd8..549949c6 100644
--- a/src/main/include/log4cxx/ndc.h
+++ b/src/main/include/log4cxx/ndc.h
@@ -26,65 +26,53 @@ namespace log4cxx
 {
 
 /**
-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.
-
-<p>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
+A <em>Nested Diagnostic Context</em>, 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.
-
-<p>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.
-
-<p><em><b>note that ndcs are managed on a per thread
-basis</b></em>. ndc operations such as #push,
-#pop, #clear and #getDepth
-affect the ndc of the <em>current</em> thread only. ndcs of other
-threads remain unaffected.
-
-<p>for example, a servlet 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 #push
-operation. simply put,
-
-<p><ul>
- <li>contexts can be nested.
-
- <p><li>when entering a context, call <code>ndc.push</code>. as a
- side effect, if there is no nested diagnostic context for the
- current thread, this method will create it.
-
- <p><li>when leaving a context, call <code>ndc.pop</code>.
-
- <p><li><b>when exiting a thread make sure to call #remove
- </b>.
+Interleaved log output can still be meaningful if each log entry
+from different contexts have a distinctive stamp.
+This is where contexts come into play.
+
+#NDC provides a constructor and destructor which simply call the #push and
+#pop methods, allowing for automatic cleanup when the current scope ends.
+
+#NDC operations such as #push, #pop, #clear and #remove
+affect only logging events emitted in the <em>calling</em> thread.
+The contexts of other threads are not changed.
+That is, <em><b>contexts are managed on a per thread basis</b></em>.
+
+For example, a servlet can build a per client request context
+consisting of the client's host name and other information contained in
+the the request. <em>Cookies</em> are another source of distinctive
+information.
+
+Contexts can be nested:
+<ul>
+ <li>when entering a context, initialize a <code>log4cxx::NDC</code>
+ type variable with a distinctive string.
+ If there is no nested diagnostic context for the
+ current thread, a NDC stack will be created.
+ The distinctive string will be automatically removed from the
+ current thread's context stack when the variable goes out of scope.
+
+ <li>when exiting a thread call NDC::remove to deal with any
+ #push operation not matched with a corresponding #pop.
 </ul>
 
-<p>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.
-
-<p>if configured to do so, PatternLayout and
-TTCCLayout instances automatically retrieve the nested diagnostic
+If configured to do so, PatternLayout, xml::XMLLayout and
+JSONLayout instances automatically retrieve the nested diagnostic
 context for the current thread without any user intervention.
-hence, even if a servlet 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.
-
-<p>heavy duty systems should call the #remove method when
-leaving the run method of a thread. this ensures that the memory
-used by the thread can be freed by the java garbage
-collector. there is a mechanism to lazily remove references to dead
-threads. in practice, this means that you can be a little sloppy
-and sometimes forget to call #remove before exiting a
-thread.
+hence, even if a process is serving multiple clients simultaneously,
+the logging events emanating from the same code
+(belonging to the same logger)
+can still be distinguished because each client
+request will have a different tag.
+
+#NDC 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.
 
 */
 class LOG4CXX_EXPORT NDC
@@ -97,21 +85,15 @@ class LOG4CXX_EXPORT NDC
 		typedef std::stack<DiagnosticContext> Stack;
 
 		/**
-		 Creates a nested diagnostic context.
-		 Since java performs no automatic cleanup of objects when a
-		 scope is left, in log4j push() and pop() must be used
-		 to manage the NDC. For convenience, log4cxx provides
-		 an NDC constructor and destructor which simply call the push() and
-		 pop() methods, allowing for automatic cleanup when the current
-		 scope ends.
-
-		 @param message The new diagnostic context information.
+		 Add \c message onto the context stack.
 		 @see The #push method.
+
+		 @param message The text added to the diagnostic context information.
 		 */
 		NDC(const std::string& message);
 
 		/**
-		Removes the topmost element from the NDC stack.
+		Remove the topmost element from the context stack associated with the current thread.
 
 		@see The #pop method.
 		*/
@@ -171,90 +153,75 @@ class LOG4CXX_EXPORT NDC
 		static bool empty();
 
 		/**
-		Pop top value off stack.
-		@return top value.
+		Get the value at the top of the stack
+		associated with the current thread and then remove it.
+		<p>The returned value is the value that was pushed last. If no
+		context is available, then the empty string "" is returned.
+		@return String The text of the innermost diagnostic context.
 		*/
 		static LogString pop();
 		/**
-		Pop top value off stack.
+		Append to \c buf the top value in the stack associated with the current thread and then remove it.
 		@param buf to which top value is appended.
 		@return true if NDC contained at least one value.
 		*/
 		static bool pop(std::string& buf);
 
 		/**
-		Looks at the last diagnostic context at the top of this NDC
-		without removing it.
+		Get the value at the top of the stack
+		associated with the current thread without removing it.
 		<p>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.
+		@return String The text of the innermost diagnostic context.
 		*/
 		static LogString peek();
 		/**
-		Get top value without removing value.
+		Append to \c buf the top value in the stack associated with the current thread without removing it.
 		@param buf to which top value is appended.
 		@return true if NDC contained at least one value.
 		*/
 		static bool peek(std::string& buf);
 
 		/**
-		Push new diagnostic context information for the current thread.
+		Add \c message to the stack associated with the current thread.
 		<p>The contents of the <code>message</code> parameter is
 		determined solely by the client.
-		@param message The new diagnostic context information.
+		@param message The text added to the diagnostic context information.
 		*/
 		static void push(const std::string& message);
 		/**
-		Push new diagnostic context information for the current thread.
+		Add \c message to the stack associated with the current thread.
 		<p>The contents of the <code>message</code> parameter is
 		determined solely by the client.
-		@param message The new diagnostic context information.
+		@param message The text added to the diagnostic context information.
 		*/
 		static void pushLS(const LogString& message);
 
 		/**
-		Remove the diagnostic context for this thread.
-		<p>Each thread that created a diagnostic context by calling
-		#push should call this method before exiting. Otherwise,
-		the memory used by the <b>thread</b> cannot be reclaimed by the
-		VM.
-		<p>As this is such an important problem in heavy duty systems and
-		because it is difficult to always guarantee that the remove
-		method is called before exiting a thread, this method has been
-		augmented to lazily remove references to dead threads. In
-		practice, this means that you can be a little sloppy and
-		occasionally forget to call #remove before exiting a
-		thread. However, you must call <code>remove</code> sometime. If
-		you never call it, then your application is sure to run out of
-		memory.
+		Remove all the diagnostic context data for this thread.
+		<p>A thread that adds to a diagnostic context by calling
+		#push should call this method before exiting
+		to prevent unbounded memory usage.
 		*/
 		static void remove();
 
 #if LOG4CXX_WCHAR_T_API
 		/**
-		  Creates a nested diagnostic context.
-		  Since java performs no automatic cleanup of objects when a
-		  scope is left, in log4j push() and pop() must be used
-		  to manage the NDC. For convenience, log4cxx provides
-		  an NDC constructor and destructor which simply call the push() and
-		  pop() methods, allowing for automatic cleanup when the current
-		  scope ends.
-
-		  @param message The new diagnostic context information.
-		  @see The #push method.
+		 Add \c message onto the context stack.
+		 @see The #push method.
+
+		 @param message The text added to the diagnostic context information.
 		  */
 		NDC(const std::wstring& message);
 		/**
-		Push new diagnostic context information for the current thread.
-		<p>The contents of the <code>message</code> parameter is
-		determined solely by the client.
-		@param message The new diagnostic context information.
+		Add \c message to the stack associated with the current thread.
+		@param message The text added to the diagnostic context information.
 		*/
 		static void push(const std::wstring& message);
 		/**
-		 *   Appends the current NDC content to the provided string.
-		 *   @param dst destination.
-		 *   @return true if NDC value set.
+		Append to \c dst the top value in the stack associated with the current thread without removing it.
+		@param dst to which top value is appended.
+		@return true if NDC contained at least one value.
 		 */
 		static bool peek(std::wstring& dst);
 		/**
@@ -266,69 +233,55 @@ class LOG4CXX_EXPORT NDC
 #endif
 #if LOG4CXX_UNICHAR_API
 		/**
-		  Creates a nested diagnostic context.
-		  Since java performs no automatic cleanup of objects when a
-		  scope is left, in log4j push() and pop() must be used
-		  to manage the NDC. For convenience, log4cxx provides
-		  an NDC constructor and destructor which simply call the push() and
-		  pop() methods, allowing for automatic cleanup when the current
-		  scope ends.
-
-		  @param message The new diagnostic context information.
-		  @see The #push method.
-		  */
+		 Add \c message onto the context stack.
+		 @see The #push method.
+
+		 @param message The text added to the diagnostic context information.
+		*/
 		NDC(const std::basic_string<UniChar>& message);
 		/**
-		Push new diagnostic context information for the current thread.
+		Add \c message to the stack associated with the current thread.
 		<p>The contents of the <code>message</code> parameter is
 		determined solely by the client.
-		@param message The new diagnostic context information.
+		@param message The text added to the diagnostic context information.
 		*/
 		static void push(const std::basic_string<UniChar>& message);
 		/**
-		 *   Appends the current NDC content to the provided string.
-		 *   @param dst destination.
-		 *   @return true if NDC value set.
+		Append to \c dst the top value in the stack associated with the current thread without removing it.
+		@param dst to which top value is appended.
+		@return true if NDC contained at least one value.
 		 */
 		static bool peek(std::basic_string<UniChar>& dst);
 		/**
-		 *   Appends the current NDC content to the provided string and removes the value from the NDC.
-		 *   @param dst destination.
-		 *   @return true if NDC value set.
+		Append to \c dst the top value in the stack associated with the current thread and then remove it.
+		@param dst to which top value is appended.
+		@return true if NDC contained at least one value.
 		 */
 		static bool pop(std::basic_string<UniChar>& dst);
 #endif
 #if LOG4CXX_CFSTRING_API
 		/**
-		  Creates a nested diagnostic context.
-		  Since java performs no automatic cleanup of objects when a
-		  scope is left, in log4j push() and pop() must be used
-		  to manage the NDC. For convenience, log4cxx provides
-		  an NDC constructor and destructor which simply call the push() and
-		  pop() methods, allowing for automatic cleanup when the current
-		  scope ends.
-
-		  @param message The new diagnostic context information.
-		  @see The #push method.
+		 Add \c message onto the context stack.
+		 @see The #push method.
+
+		 @param message The text added to the diagnostic context information.
 		  */
 		NDC(const CFStringRef& message);
 		/**
-		Push new diagnostic context information for the current thread.
-		<p>The contents of the <code>message</code> parameter is
-		determined solely by the client.
-		@param message The new diagnostic context information.
+		Add \c message to the stack associated with the current thread.
+		@param message The text added to the diagnostic context information.
 		*/
 		static void push(const CFStringRef& message);
 		/**
-		 *   Gets the current NDC value.
-		 *   @param dst destination.
-		 *   @return true if NDC value set.
+		Append to \c dst the top value in the stack associated with the current thread without removing it.
+		@param dst to which top value is appended.
+		@return true if NDC contained at least one value.
 		 */
 		static bool peek(CFStringRef& dst);
 		/**
-		 *  Gets and removes the current NDC value.
-		 *   @param dst destination.
-		 *   @return true if NDC value set.
+		Append to \c dst the top value in the stack associated with the current thread and then remove it.
+		@param dst to which top value is appended.
+		@return true if NDC contained at least one value.
 		 */
 		static bool pop(CFStringRef& dst);
 #endif
diff --git a/src/site/markdown/1-usage.md b/src/site/markdown/1-usage.md
index 5ce8aecf..4cb5694e 100644
--- a/src/site/markdown/1-usage.md
+++ b/src/site/markdown/1-usage.md
@@ -24,6 +24,7 @@ Usage {#usage-overview}
 See the following pages for usage information:
 
 * @subpage usage
+* @subpage nested-diagnostic-contexts
 * @subpage filters
 * @subpage threading
 * @subpage extending-log4cxx
diff --git a/src/site/markdown/nested-diagnostic-contexts.md b/src/site/markdown/nested-diagnostic-contexts.md
new file mode 100644
index 00000000..994d53a8
--- /dev/null
+++ b/src/site/markdown/nested-diagnostic-contexts.md
@@ -0,0 +1,69 @@
+Nested Diagnostic Contexts {#nested-diagnostic-contexts}
+===
+<!--
+ Note: License header cannot be first, as doxygen does not generate
+ cleanly if it before the '==='
+-->
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+
+Most real-world systems have to deal with multiple clients
+simultaneously. In a typical multithreaded implementation of such a
+system, different threads will handle different clients. Logging is
+especially well suited to trace and debug complex distributed
+applications. A common approach to differentiate the logging output of
+one client from another is to instantiate a new separate logger for each
+client. This promotes the proliferation of loggers and increases the
+management overhead of logging.
+
+A lighter technique is to uniquely stamp each log request initiated from
+the same client interaction. Neil Harrison described this method in the
+book "Patterns for Logging Diagnostic Messages," in *Pattern Languages
+of Program Design 3*, edited by R. Martin, D. Riehle, and F. Buschmann
+(Addison-Wesley, 1997).
+
+To uniquely stamp each request, the user pushes contextual information
+into the *Nested Diagnostic Context* (NDC) using the *log4cxx::NDC* class.
+For an example refer to \ref trivial.cpp.
+Note that all methods of the *log4cxx::NDC* class are static.
+
+The NDC is managed per thread as a *stack* of contextual information.
+Each log entry will include the entire stack
+for the current thread (for better control use *log4cxx::MDC*).
+The user is responsible for placing the correct information in the NDC
+by using the *push* and *pop* methods at
+a few well-defined points in the code. In contrast, the per-client
+logger approach commands extensive changes in the code.
+
+To illustrate this point, let us take the example of a servlet
+delivering content to numerous clients. The servlet can build the NDC at
+the very beginning of the request before executing other code. The
+contextual information can be the client's host name and other
+information inherent to the request, typically information contained in
+cookies. Hence, even if the servlet is serving multiple clients
+simultaneously, the logs initiated by the same code, i.e. belonging to
+the same logger, can still be distinguished because each client request
+will have a different NDC stack. Contrast this with the complexity of
+passing a freshly instantiated logger to all code exercised during the
+client's request.
+
+Nevertheless, some sophisticated applications, such as virtual hosting
+web servers, must log differently depending on the virtual host context
+and also depending on the software component issuing the request. Recent
+Log4cxx releases support multiple hierarchy trees. This enhancement
+allows each virtual host to possess its own copy of the logger
+hierarchy.
diff --git a/src/site/markdown/usage.md b/src/site/markdown/usage.md
index 14010d19..2450fdbb 100644
--- a/src/site/markdown/usage.md
+++ b/src/site/markdown/usage.md
@@ -549,55 +549,6 @@ To use automatic configuration with a non-standard file name
 create and use your own wrapper for [getLogger](@ref log4cxx.LogManager.getLogger).
 A full example can be seen in the \ref com/foo/config3.cpp file.
 
-# Nested Diagnostic Contexts {#nested-diagnostic-contexts}
-
-Most real-world systems have to deal with multiple clients
-simultaneously. In a typical multithreaded implementation of such a
-system, different threads will handle different clients. Logging is
-especially well suited to trace and debug complex distributed
-applications. A common approach to differentiate the logging output of
-one client from another is to instantiate a new separate logger for each
-client. This promotes the proliferation of loggers and increases the
-management overhead of logging.
-
-A lighter technique is to uniquely stamp each log request initiated from
-the same client interaction. Neil Harrison described this method in the
-book "Patterns for Logging Diagnostic Messages," in *Pattern Languages
-of Program Design 3*, edited by R. Martin, D. Riehle, and F. Buschmann
-(Addison-Wesley, 1997).
-
-To uniquely stamp each request, the user pushes contextual information
-into the *Nested Diagnostic Context* (NDC) using the *log4cxx::NDC* class.
-For an example refer to \ref trivial.cpp.
-Note that all methods of the *log4cxx::NDC* class are static.
-
-The NDC is managed per thread as a *stack* of contextual information.
-Each log entry will include the entire stack
-for the current thread (for better control use *log4cxx::MDC*).
-The user is responsible for placing the correct information in the NDC
-by using the *push* and *pop* methods at
-a few well-defined points in the code. In contrast, the per-client
-logger approach commands extensive changes in the code.
-
-To illustrate this point, let us take the example of a servlet
-delivering content to numerous clients. The servlet can build the NDC at
-the very beginning of the request before executing other code. The
-contextual information can be the client's host name and other
-information inherent to the request, typically information contained in
-cookies. Hence, even if the servlet is serving multiple clients
-simultaneously, the logs initiated by the same code, i.e. belonging to
-the same logger, can still be distinguished because each client request
-will have a different NDC stack. Contrast this with the complexity of
-passing a freshly instantiated logger to all code exercised during the
-client's request.
-
-Nevertheless, some sophisticated applications, such as virtual hosting
-web servers, must log differently depending on the virtual host context
-and also depending on the software component issuing the request. Recent
-Log4cxx releases support multiple hierarchy trees. This enhancement
-allows each virtual host to possess its own copy of the logger
-hierarchy.
-
 # Logging Custom Types {#custom-types}
 
 Often, the data that needs to be logged is not just standard data types