001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 * 
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 * 
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018//      Contributors:      Dan Milstein 
019//                         Ray Millard
020
021package org.apache.log4j;
022
023import java.util.Hashtable;
024import java.util.Stack;
025import java.util.Enumeration;
026import java.util.Vector;
027
028import org.apache.log4j.helpers.LogLog;
029
030/**
031   The NDC class implements <i>nested diagnostic contexts</i> as
032   defined by Neil Harrison in the article "Patterns for Logging
033   Diagnostic Messages" part of the book "<i>Pattern Languages of
034   Program Design 3</i>" edited by Martin et al.
035
036   <p>A Nested Diagnostic Context, or NDC in short, is an instrument
037   to distinguish interleaved log output from different sources. Log
038   output is typically interleaved when a server handles multiple
039   clients near-simultaneously.
040
041   <p>Interleaved log output can still be meaningful if each log entry
042   from different contexts had a distinctive stamp. This is where NDCs
043   come into play.
044
045   <p><em><b>Note that NDCs are managed on a per thread
046   basis</b></em>. NDC operations such as {@link #push push}, {@link
047   #pop}, {@link #clear}, {@link #getDepth} and {@link #setMaxDepth}
048   affect the NDC of the <em>current</em> thread only. NDCs of other
049   threads remain unaffected.
050
051   <p>For example, a servlet can build a per client request NDC
052   consisting the clients host name and other information contained in
053   the the request. <em>Cookies</em> are another source of distinctive
054   information. To build an NDC one uses the {@link #push push}
055   operation. Simply put,
056
057   <p><ul>
058     <li>Contexts can be nested.
059
060     <p><li>When entering a context, call <code>NDC.push</code>. As a
061     side effect, if there is no nested diagnostic context for the
062     current thread, this method will create it.
063
064     <p><li>When leaving a context, call <code>NDC.pop</code>.
065
066     <p><li><b>When exiting a thread make sure to call {@link #remove
067     NDC.remove()}</b>.  
068   </ul>
069   
070   <p>There is no penalty for forgetting to match each
071   <code>push</code> operation with a corresponding <code>pop</code>,
072   except the obvious mismatch between the real application context
073   and the context set in the NDC.
074
075   <p>If configured to do so, {@link PatternLayout} and {@link
076   TTCCLayout} instances automatically retrieve the nested diagnostic
077   context for the current thread without any user intervention.
078   Hence, even if a servlet is serving multiple clients
079   simultaneously, the logs emanating from the same code (belonging to
080   the same category) can still be distinguished because each client
081   request will have a different NDC tag.
082
083   <p>Heavy duty systems should call the {@link #remove} method when
084   leaving the run method of a thread. This ensures that the memory
085   used by the thread can be freed by the Java garbage
086   collector. There is a mechanism to lazily remove references to dead
087   threads. In practice, this means that you can be a little sloppy
088   and sometimes forget to call {@link #remove} before exiting a
089   thread.
090   
091   <p>A thread may inherit the nested diagnostic context of another
092   (possibly parent) thread using the {@link #inherit inherit}
093   method. A thread may obtain a copy of its NDC with the {@link
094   #cloneStack cloneStack} method and pass the reference to any other
095   thread, in particular to a child.
096   
097   @author Ceki G&uuml;lc&uuml;
098   @since 0.7.0
099  
100*/
101 
102public class NDC {
103
104  // The synchronized keyword is not used in this class. This may seem
105  // dangerous, especially since the class will be used by
106  // multiple-threads. In particular, all threads share the same
107  // hashtable (the "ht" variable). This is OK since java hashtables
108  // are thread safe. Same goes for Stacks.
109
110  // More importantly, when inheriting diagnostic contexts the child
111  // thread is handed a clone of the parent's NDC.  It follows that
112  // each thread has its own NDC (i.e. stack).
113
114  static Hashtable ht = new Hashtable();
115
116  static int pushCounter = 0; // the number of times push has been called
117                              // after the latest call to lazyRemove
118
119  // The number of times we allow push to be called before we call lazyRemove
120  // 5 is a relatively small number. As such, lazyRemove is not called too
121  // frequently. We thus avoid the cost of creating an Enumeration too often.
122  // The higher this number, the longer is the avarage period for which all
123  // logging calls in all threads are blocked.
124  static final int REAP_THRESHOLD = 5;
125  
126  // No instances allowed.
127  private NDC() {}
128  
129  /**
130   *   Get NDC stack for current thread.
131   *   @return NDC stack for current thread.
132   */
133  private static Stack getCurrentStack() {
134      if (ht != null) {
135          return (Stack) ht.get(Thread.currentThread());
136      }
137      return null;
138  }
139
140
141  /**
142     Clear any nested diagnostic information if any. This method is
143     useful in cases where the same thread can be potentially used
144     over and over in different unrelated contexts.
145
146     <p>This method is equivalent to calling the {@link #setMaxDepth}
147     method with a zero <code>maxDepth</code> argument.
148     
149     @since 0.8.4c */
150  public
151  static
152  void clear() {
153    Stack stack = getCurrentStack();    
154    if(stack != null) 
155      stack.setSize(0);    
156  }
157
158  
159  /**
160     Clone the diagnostic context for the current thread.
161
162     <p>Internally a diagnostic context is represented as a stack.  A
163     given thread can supply the stack (i.e. diagnostic context) to a
164     child thread so that the child can inherit the parent thread's
165     diagnostic context.
166
167     <p>The child thread uses the {@link #inherit inherit} method to
168     inherit the parent's diagnostic context.
169     
170     @return Stack A clone of the current thread's  diagnostic context.
171
172  */
173  public
174  static
175  Stack cloneStack() {
176    Stack stack = getCurrentStack();
177    if(stack == null)
178      return null;
179    else {
180      return (Stack) stack.clone();
181    }
182  }
183
184  
185  /**
186     Inherit the diagnostic context of another thread.
187
188     <p>The parent thread can obtain a reference to its diagnostic
189     context using the {@link #cloneStack} method.  It should
190     communicate this information to its child so that it may inherit
191     the parent's diagnostic context.
192
193     <p>The parent's diagnostic context is cloned before being
194     inherited. In other words, once inherited, the two diagnostic
195     contexts can be managed independently.
196     
197     <p>In java, a child thread cannot obtain a reference to its
198     parent, unless it is directly handed the reference. Consequently,
199     there is no client-transparent way of inheriting diagnostic
200     contexts. Do you know any solution to this problem?
201
202     @param stack The diagnostic context of the parent thread.
203
204  */
205  public
206  static
207  void inherit(Stack stack) {
208    if(stack != null)
209      ht.put(Thread.currentThread(), stack);
210  }
211
212
213  /**
214     <font color="#FF4040"><b>Never use this method directly, use the {@link
215     org.apache.log4j.spi.LoggingEvent#getNDC} method instead</b></font>.
216  */
217  static
218  public
219  String get() {
220    Stack s = getCurrentStack();
221    if(s != null && !s.isEmpty()) 
222      return ((DiagnosticContext) s.peek()).fullMessage;
223    else
224      return null;
225  }
226  
227  /**
228   * Get the current nesting depth of this diagnostic context.
229   *
230   * @see #setMaxDepth
231   * @since 0.7.5
232   */
233  public
234  static
235  int getDepth() {
236    Stack stack = getCurrentStack();          
237    if(stack == null)
238      return 0;
239    else
240      return stack.size();      
241  }
242
243  private
244  static
245  void lazyRemove() {
246    if (ht == null) return;
247     
248    // The synchronization on ht is necessary to prevent JDK 1.2.x from
249    // throwing ConcurrentModificationExceptions at us. This sucks BIG-TIME.
250    // One solution is to write our own hashtable implementation.
251    Vector v;
252    
253    synchronized(ht) {
254      // Avoid calling clean-up too often.
255      if(++pushCounter <= REAP_THRESHOLD) {
256        return; // We release the lock ASAP.
257      } else {
258        pushCounter = 0; // OK let's do some work.
259      }
260
261      int misses = 0;
262      v = new Vector(); 
263      Enumeration enumeration = ht.keys();
264      // We give up after 4 straigt missses. That is 4 consecutive
265      // inspected threads in 'ht' that turn out to be alive.
266      // The higher the proportion on dead threads in ht, the higher the
267      // chances of removal.
268      while(enumeration.hasMoreElements() && (misses <= 4)) {
269        Thread t = (Thread) enumeration.nextElement();
270        if(t.isAlive()) {
271          misses++;
272        } else {
273          misses = 0;
274          v.addElement(t);
275        }
276      }
277    } // synchronized
278
279    int size = v.size();
280    for(int i = 0; i < size; i++) {
281      Thread t = (Thread) v.elementAt(i);
282      LogLog.debug("Lazy NDC removal for thread [" + t.getName() + "] ("+ 
283                   ht.size() + ").");
284      ht.remove(t);
285    }
286  }
287
288  /**
289     Clients should call this method before leaving a diagnostic
290     context.
291
292     <p>The returned value is the value that was pushed last. If no
293     context is available, then the empty string "" is returned.
294     
295     @return String The innermost diagnostic context.
296     
297     */
298  public
299  static
300  String pop() {
301    Stack stack = getCurrentStack();
302    if(stack != null && !stack.isEmpty()) 
303      return ((DiagnosticContext) stack.pop()).message;
304    else
305      return "";
306  }
307
308  /**
309     Looks at the last diagnostic context at the top of this NDC
310     without removing it.
311
312     <p>The returned value is the value that was pushed last. If no
313     context is available, then the empty string "" is returned.
314     
315     @return String The innermost diagnostic context.
316     
317     */
318  public
319  static
320  String peek() {
321    Stack stack = getCurrentStack();
322    if(stack != null && !stack.isEmpty())
323      return ((DiagnosticContext) stack.peek()).message;
324    else
325      return "";
326  }
327  
328  /**
329     Push new diagnostic context information for the current thread.
330
331     <p>The contents of the <code>message</code> parameter is
332     determined solely by the client.  
333     
334     @param message The new diagnostic context information.  */
335  public
336  static
337  void push(String message) {
338    Stack stack = getCurrentStack();
339      
340    if(stack == null) {
341      DiagnosticContext dc = new DiagnosticContext(message, null);      
342      stack = new Stack();
343      Thread key = Thread.currentThread();
344      ht.put(key, stack);
345      stack.push(dc);
346    } else if (stack.isEmpty()) {
347      DiagnosticContext dc = new DiagnosticContext(message, null);            
348      stack.push(dc);
349    } else {
350      DiagnosticContext parent = (DiagnosticContext) stack.peek();
351      stack.push(new DiagnosticContext(message, parent));
352    }    
353  }
354
355  /**
356     Remove the diagnostic context for this thread.
357
358     <p>Each thread that created a diagnostic context by calling
359     {@link #push} should call this method before exiting. Otherwise,
360     the memory used by the <b>thread</b> cannot be reclaimed by the
361     VM.
362
363     <p>As this is such an important problem in heavy duty systems and
364     because it is difficult to always guarantee that the remove
365     method is called before exiting a thread, this method has been
366     augmented to lazily remove references to dead threads. In
367     practice, this means that you can be a little sloppy and
368     occasionally forget to call {@link #remove} before exiting a
369     thread. However, you must call <code>remove</code> sometime. If
370     you never call it, then your application is sure to run out of
371     memory.
372     
373  */
374  static
375  public
376  void remove() {
377    if (ht != null) {
378        ht.remove(Thread.currentThread());
379    
380        // Lazily remove dead-thread references in ht.
381        lazyRemove();
382    }
383  }
384
385  /**
386     Set maximum depth of this diagnostic context. If the current
387     depth is smaller or equal to <code>maxDepth</code>, then no
388     action is taken.
389
390     <p>This method is a convenient alternative to multiple {@link
391     #pop} calls. Moreover, it is often the case that at the end of
392     complex call sequences, the depth of the NDC is
393     unpredictable. The <code>setMaxDepth</code> method circumvents
394     this problem.
395
396     <p>For example, the combination
397     <pre>
398       void foo() {
399       &nbsp;  int depth = NDC.getDepth();
400
401       &nbsp;  ... complex sequence of calls
402
403       &nbsp;  NDC.setMaxDepth(depth);
404       }
405     </pre>
406
407     ensures that between the entry and exit of foo the depth of the
408     diagnostic stack is conserved.
409     
410     @see #getDepth
411     @since 0.7.5 */
412  static
413  public
414  void setMaxDepth(int maxDepth) {
415    Stack stack = getCurrentStack();    
416    if(stack != null && maxDepth < stack.size()) 
417      stack.setSize(maxDepth);
418  }
419  
420  // =====================================================================
421   private static class DiagnosticContext {
422
423    String fullMessage;
424    String message;
425    
426    DiagnosticContext(String message, DiagnosticContext parent) {
427      this.message = message;
428      if(parent != null) {
429        fullMessage = parent.fullMessage + ' ' + message;
430      } else {
431        fullMessage = message;
432      }
433    }
434  }
435}
436