| /* |
| * Copyright 1999,2004 The Apache Software Foundation. |
| * |
| * 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. |
| */ |
| |
| |
| // Contributors: Dan Milstein |
| // Ray Millard |
| // Ray DeCampo |
| package org.apache.log4j; |
| |
| import java.util.Stack; |
| |
| |
| /** |
| 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 |
| 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 {@link #push 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. |
| |
| <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 {@link #push 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>As of log4j 1.3, it is no longer necessary to call {@link #remove |
| NDC.remove()} when exiting a thread.</b>. |
| </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, {@link PatternLayout} and {@link |
| TTCCLayout} 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 category) can still be distinguished because each client |
| request will have a different NDC tag. |
| |
| <p>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. |
| |
| @author Ceki Gülcü |
| @since 0.7.0 |
| |
| */ |
| public class NDC { |
| // The synchronized keyword is not used in this class. This may seem |
| // dangerous, especially since the class will be used by |
| // multiple-threads. |
| // This is OK since java Stacks are thread safe. |
| // More importantly, when inheriting diagnostic contexts the child |
| // thread is handed a clone of the parent's NDC. It follows that |
| // each thread has its own NDC (i.e. stack). |
| private static final ThreadLocal tl = new ThreadLocal(); |
| static int pushCounter = 0; // the number of times push has been called |
| // after the latest call to lazyRemove |
| static final int REAP_THRESHOLD = 5; |
| |
| // No instances allowed. |
| private NDC() { |
| } |
| |
| /** |
| 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. |
| |
| <p>This method is equivalent to calling the {@link #setMaxDepth} |
| method with a zero <code>maxDepth</code> argument. |
| |
| @since 0.8.4c */ |
| public static void clear() { |
| Stack stack = (Stack) tl.get(); |
| |
| if (stack != null) { |
| stack.setSize(0); |
| } |
| } |
| |
| /** |
| Clone the diagnostic context for the current thread. |
| |
| <p>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. |
| |
| <p>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. |
| |
| */ |
| public static Stack cloneStack() { |
| Object o = tl.get(); |
| |
| if (o == null) { |
| return null; |
| } else { |
| Stack stack = (Stack) o; |
| |
| return (Stack) stack.clone(); |
| } |
| } |
| |
| /** |
| Inherit the diagnostic context of another thread. |
| |
| <p>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. |
| |
| <p>The parent's diagnostic context is cloned before being |
| inherited. In other words, once inherited, the two diagnostic |
| contexts can be managed independently. |
| |
| <p>In java, a child thread cannot obtain a reference to its |
| parent, unless it is directly handed the reference. Consequently, |
| there is no client-transparent way of inheriting diagnostic |
| contexts. Do you know any solution to this problem? |
| |
| @param stack The diagnostic context of the parent thread. |
| |
| */ |
| public static void inherit(Stack stack) { |
| if (stack != null) { |
| tl.set(stack); |
| } |
| } |
| |
| /** |
| <font color="#FF4040"><b>Never use this method directly, use the {@link |
| org.apache.log4j.spi.LoggingEvent#getNDC} method instead</b></font>. |
| */ |
| public static String get() { |
| Stack s = (Stack) tl.get(); |
| |
| if ((s != null) && !s.isEmpty()) { |
| return ((DiagnosticContext) s.peek()).fullMessage; |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| Get the current nesting depth of this diagnostic context. |
| |
| @see #setMaxDepth |
| @since 0.7.5 |
| */ |
| public static int getDepth() { |
| Stack stack = (Stack) tl.get(); |
| |
| if (stack == null) { |
| return 0; |
| } else { |
| return stack.size(); |
| } |
| } |
| |
| /** |
| Clients should call this method before leaving a diagnostic |
| context. |
| |
| <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. |
| |
| */ |
| public static String pop() { |
| Stack stack = (Stack) tl.get(); |
| |
| if ((stack != null) && !stack.isEmpty()) { |
| return ((DiagnosticContext) stack.pop()).message; |
| } else { |
| return ""; |
| } |
| } |
| |
| /** |
| Looks at the last diagnostic context at the top of this NDC |
| 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. |
| |
| */ |
| public static String peek() { |
| Stack stack = (Stack) tl.get(); |
| |
| if ((stack != null) && !stack.isEmpty()) { |
| return ((DiagnosticContext) stack.peek()).message; |
| } else { |
| return ""; |
| } |
| } |
| |
| /** |
| 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. */ |
| public static void push(String message) { |
| Stack stack = (Stack) tl.get(); |
| |
| if (stack == null) { |
| DiagnosticContext dc = new DiagnosticContext(message, null); |
| stack = new Stack(); |
| tl.set(stack); |
| stack.push(dc); |
| } else if (stack.isEmpty()) { |
| DiagnosticContext dc = new DiagnosticContext(message, null); |
| stack.push(dc); |
| } else { |
| DiagnosticContext parent = (DiagnosticContext) stack.peek(); |
| stack.push(new DiagnosticContext(message, parent)); |
| } |
| } |
| |
| /** |
| Remove the diagnostic context for this thread. |
| |
| <p>As of log4j 1.3, the <code>NDC</code> class uses {@link ThreadLocal} |
| technology to store the context. It is no longer necessary to call this |
| method. It remains for backwards compatibility. |
| */ |
| public static 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. |
| |
| <p>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. |
| |
| <p>For example, the combination |
| <pre> |
| void foo() { |
| int 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. |
| |
| @see #getDepth |
| @since 0.7.5 */ |
| public static void setMaxDepth(int maxDepth) { |
| Stack stack = (Stack) tl.get(); |
| |
| if ((stack != null) && (maxDepth < stack.size())) { |
| stack.setSize(maxDepth); |
| } |
| } |
| |
| // ===================================================================== |
| private static class DiagnosticContext { |
| String fullMessage; |
| String message; |
| |
| DiagnosticContext(String message, DiagnosticContext parent) { |
| this.message = message; |
| |
| if (parent != null) { |
| fullMessage = parent.fullMessage + ' ' + message; |
| } else { |
| fullMessage = message; |
| } |
| } |
| } |
| } |