Home » apache-log4j-1.2.15 » org.apache » log4j » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   //      Contributors:      Dan Milstein 
   19   //                         Ray Millard
   20   
   21   package org.apache.log4j;
   22   
   23   import java.util.Hashtable;
   24   import java.util.Stack;
   25   import java.util.Enumeration;
   26   import java.util.Vector;
   27   
   28   import org.apache.log4j.helpers.LogLog;
   29   
   30   /**
   31      The NDC class implements <i>nested diagnostic contexts</i> as
   32      defined by Neil Harrison in the article "Patterns for Logging
   33      Diagnostic Messages" part of the book "<i>Pattern Languages of
   34      Program Design 3</i>" edited by Martin et al.
   35   
   36      <p>A Nested Diagnostic Context, or NDC in short, is an instrument
   37      to distinguish interleaved log output from different sources. Log
   38      output is typically interleaved when a server handles multiple
   39      clients near-simultaneously.
   40   
   41      <p>Interleaved log output can still be meaningful if each log entry
   42      from different contexts had a distinctive stamp. This is where NDCs
   43      come into play.
   44   
   45      <p><em><b>Note that NDCs are managed on a per thread
   46      basis</b></em>. NDC operations such as {@link #push push}, {@link
   47      #pop}, {@link #clear}, {@link #getDepth} and {@link #setMaxDepth}
   48      affect the NDC of the <em>current</em> thread only. NDCs of other
   49      threads remain unaffected.
   50   
   51      <p>For example, a servlet can build a per client request NDC
   52      consisting the clients host name and other information contained in
   53      the the request. <em>Cookies</em> are another source of distinctive
   54      information. To build an NDC one uses the {@link #push push}
   55      operation. Simply put,
   56   
   57      <p><ul>
   58        <li>Contexts can be nested.
   59   
   60        <p><li>When entering a context, call <code>NDC.push</code>. As a
   61        side effect, if there is no nested diagnostic context for the
   62        current thread, this method will create it.
   63   
   64        <p><li>When leaving a context, call <code>NDC.pop</code>.
   65   
   66        <p><li><b>When exiting a thread make sure to call {@link #remove
   67        NDC.remove()}</b>.  
   68      </ul>
   69      
   70      <p>There is no penalty for forgetting to match each
   71      <code>push</code> operation with a corresponding <code>pop</code>,
   72      except the obvious mismatch between the real application context
   73      and the context set in the NDC.
   74   
   75      <p>If configured to do so, {@link PatternLayout} and {@link
   76      TTCCLayout} instances automatically retrieve the nested diagnostic
   77      context for the current thread without any user intervention.
   78      Hence, even if a servlet is serving multiple clients
   79      simultaneously, the logs emanating from the same code (belonging to
   80      the same category) can still be distinguished because each client
   81      request will have a different NDC tag.
   82   
   83      <p>Heavy duty systems should call the {@link #remove} method when
   84      leaving the run method of a thread. This ensures that the memory
   85      used by the thread can be freed by the Java garbage
   86      collector. There is a mechanism to lazily remove references to dead
   87      threads. In practice, this means that you can be a little sloppy
   88      and sometimes forget to call {@link #remove} before exiting a
   89      thread.
   90      
   91      <p>A thread may inherit the nested diagnostic context of another
   92      (possibly parent) thread using the {@link #inherit inherit}
   93      method. A thread may obtain a copy of its NDC with the {@link
   94      #cloneStack cloneStack} method and pass the reference to any other
   95      thread, in particular to a child.
   96      
   97      @author Ceki G&uuml;lc&uuml;
   98      @since 0.7.0
   99     
  100   */
  101    
  102   public 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       ht.remove(Thread.currentThread());
  378       
  379       // Lazily remove dead-thread references in ht.
  380       lazyRemove();    
  381     }
  382   
  383     /**
  384        Set maximum depth of this diagnostic context. If the current
  385        depth is smaller or equal to <code>maxDepth</code>, then no
  386        action is taken.
  387   
  388        <p>This method is a convenient alternative to multiple {@link
  389        #pop} calls. Moreover, it is often the case that at the end of
  390        complex call sequences, the depth of the NDC is
  391        unpredictable. The <code>setMaxDepth</code> method circumvents
  392        this problem.
  393   
  394        <p>For example, the combination
  395        <pre>
  396          void foo() {
  397          &nbsp;  int depth = NDC.getDepth();
  398   
  399          &nbsp;  ... complex sequence of calls
  400   
  401          &nbsp;  NDC.setMaxDepth(depth);
  402          }
  403        </pre>
  404   
  405        ensures that between the entry and exit of foo the depth of the
  406        diagnostic stack is conserved.
  407        
  408        @see #getDepth
  409        @since 0.7.5 */
  410     static
  411     public
  412     void setMaxDepth(int maxDepth) {
  413       Stack stack = getCurrentStack();    
  414       if(stack != null && maxDepth < stack.size()) 
  415         stack.setSize(maxDepth);
  416     }
  417     
  418     // =====================================================================
  419      private static class DiagnosticContext {
  420   
  421       String fullMessage;
  422       String message;
  423       
  424       DiagnosticContext(String message, DiagnosticContext parent) {
  425         this.message = message;
  426         if(parent != null) {
  427   	fullMessage = parent.fullMessage + ' ' + message;
  428         } else {
  429   	fullMessage = message;
  430         }
  431       }
  432     }
  433   }
  434   

Save This Page
Home » apache-log4j-1.2.15 » org.apache » log4j » [javadoc | source]