You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2001/03/02 05:11:54 UTC

cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/util/threads ThreadPool.java

costin      01/03/01 20:11:54

  Modified:    src/share/org/apache/tomcat/util/io FileUtil.java
               src/share/org/apache/tomcat/util/log Log.java
               src/share/org/apache/tomcat/util/net PoolTcpEndpoint.java
               src/share/org/apache/tomcat/util/threads ThreadPool.java
  Added:       src/share/org/apache/tomcat/util/log LogHandler.java
                        LogManager.java
               src/share/org/apache/tomcat/util/qlog FastDateFormat.java
                        LogEntry.java Logger.java QueueLogger.java
                        package.html
  Removed:     src/share/org/apache/tomcat/util/log DefaultLogger.java
                        FastDateFormat.java LogAware.java LogEntry.java
                        Logger.java QueueLogger.java
  Log:
  util/log changes.
  
  As proposed, the actual implementation is now in util/qlog, and
  util/log contains only the base classes.
  
  Also, the code was slightly re-organized - the log registery is now
  part of LogManager ( which is of interest for the LogModule that
  sets up the loggers ), LogHandler ( which is of interest for the actual
  logger implementations - for example if you want to write an adapter for
  log4j ) and Log ( which is the only class used in tomcat, utils, modules ).
  
  The 3 classes in util/log are functional ( i.e. if you don't set any LogHandler implementation you just get the messages on System.out ).
  
  The normal use is:
  Log.getLog()
  log.log(...).
  
  Normal code shouldn't deal with anything but Log ( the other 2 are for
  logger implementations and for configuring the logger ).
  
  The code is functionally identical with what we had previously, and
  AFAIK doesn't have anything but the core functionality we need.
  
  BTW, I added few comments about the reasons to have a 2 level logger and notes
  on security ( i.e. normal code shouldn't be able to change log config )
  
  Revision  Changes    Path
  1.3       +6 -4      jakarta-tomcat/src/share/org/apache/tomcat/util/io/FileUtil.java
  
  Index: FileUtil.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/io/FileUtil.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- FileUtil.java	2001/03/01 18:05:00	1.2
  +++ FileUtil.java	2001/03/02 04:11:37	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/io/FileUtil.java,v 1.2 2001/03/01 18:05:00 larryi Exp $
  - * $Revision: 1.2 $
  - * $Date: 2001/03/01 18:05:00 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/io/FileUtil.java,v 1.3 2001/03/02 04:11:37 costin Exp $
  + * $Revision: 1.3 $
  + * $Date: 2001/03/02 04:11:37 $
    *
    * ====================================================================
    *
  @@ -126,7 +126,9 @@
   	return lookupPath + "/" + path;
       }
   
  -    static Log loghelper = new Log("tc_log", "FileUtil");
  +    // XXX tc_log is the default channel in tomcat, this component
  +    //should be able to log in a specific channel.
  +    static Log loghelper = Log.getLog("tc/FileUtil", "FileUtil");
       
       /** All the safety checks from getRealPath() and
   	DefaultServlet.
  
  
  
  1.5       +103 -114  jakarta-tomcat/src/share/org/apache/tomcat/util/log/Log.java
  
  Index: Log.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/log/Log.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- Log.java	2001/02/20 03:14:12	1.4
  +++ Log.java	2001/03/02 04:11:42	1.5
  @@ -62,11 +62,10 @@
   
   
   /**
  - * Corresponds to a log chanel - this is the main class
  - * seen by objects that need to log. 
  + * This is the main class seen by objects that need to log. 
    * 
  - * It has a preferred log name to write to; if
  - * it can't find a log with that name, it outputs to the default
  + * It has a log channel to write to; if it can't find a log with that name,
  + * it outputs to the default
    * sink.  Also prepends a descriptive name to each message
    * (usually the toString() of the calling object), so it's easier
    * to identify the source.<p>
  @@ -74,10 +73,7 @@
    * Intended for use by client classes to make it easy to do
    * reliable, consistent logging behavior, even if you don't
    * necessarily have a context, or if you haven't registered any
  - * log files yet, or if you're in a non-Tomcat application.  Not
  - * intended to supplant Logger, but to allow client objects a
  - * consistent bit of code that prepares log messages before they
  - * reach logger (and does the right thing if there is no logger).
  + * log files yet, or if you're in a non-Tomcat application.
    * <p>
    * Usage: <pre>
    * class Foo {
  @@ -92,11 +88,20 @@
    *       log.log("While doing something", e);
    *     }
    * </pre>
  + * 
  + *  As a special feature ( required in tomcat operation ) the
  + *  Log can be modified at run-time, by changing and configuring the logging
  + *  implementation ( without requiring any special change in the user code ).
  + *  That means that the  user can do a Log.getLog() at any time,
  + *  even before the logging system is fully configured. The
  + *  embeding application can then set up or change the logging details,
  + *  without any action from the log user.
    *
    * @author Alex Chaffee [alex@jguru.com]
    * @author Costin Manolache
    **/
   public class Log {
  +
       /**
        * Verbosity level codes.
        */
  @@ -109,69 +114,54 @@
   
       // name of the logger ( each logger has a unique name,
       // used as a key internally )
  -    private String logname;
  +    protected String logname;
   
       // string displayed at the beginning of each log line,
       // to identify the source
  -    private String prefix;
  +    protected String prefix;
  +
  +    /* The "real" logger. This allows the manager to change the
  +       sink/logger at runtime, and without requiring the log
  +       user to do any special action or be aware of the changes
  +    */
  +    private LogHandler proxy=new LogHandler(); // the default
  +
  +    // Used to get access to other logging channels.
  +    // Can be replaced with an application-specific impl.
  +    private static LogManager logManager=new LogManager();
   
  +
       // -------------------- Various constructors --------------------
   
  -    public Log() {
  +    protected Log(String channel, String prefix, Object owner) {
  +	this.logname=channel;
  +	this.prefix=prefix;
       }
   
       /**
  -     * Subclass constructor, for classes that want to *be* a
  -     * LogHelper, and get the log methods for free (like a mixin)
  -     **/
  -    public Log(String logname) {
  -	this.logname = logname;
  -	String cname=this.getClass().getName();
  -	this.prefix = cname.substring( cname.lastIndexOf(".") +1);
  -    }
  -    
  -    /**
        * @param logname name of log to use
        * @param owner object whose class name to use as prefix
        **/
  -    public Log(String logname, Object owner) 
  -    {
  -	this.logname = logname;
  -	String cname = owner.getClass().getName();
  -	this.prefix = cname.substring( cname.lastIndexOf(".") +1);
  -    }	
  +    public static Log getLog( String channel, String prefix ) {
  +	return logManager.getLog( channel, prefix, null );
  +    }
       
       /**
        * @param logname name of log to use
        * @param prefix string to prepend to each message
        **/
  -    public Log(String logname, String prefix) 
  -    {
  -	this.logname = logname;
  -	this.prefix = prefix;
  -    }
  -
  -    public static Log getLog( String channel, String prefix ) {
  -	Log log=new Log( channel, prefix );
  -	return log;
  -    }
  -    
       public static Log getLog( String channel, Object owner ) {
  -	// XXX return singleton
  -	Log log=new Log( channel, owner );
  -	return log;
  +	return logManager.getLog( channel, null, owner );
       }
       
       // -------------------- Log messages. --------------------
  -    // That all a client needs to know about logging !
  -    // --------------------
       
       /**
        * Logs the message with level INFORMATION
        **/
       public void log(String msg) 
       {
  -	log(msg, null, Logger.INFORMATION);
  +	log(msg, null, INFORMATION);
       }
       
       /**
  @@ -180,7 +170,7 @@
        **/
       public void log(String msg, Throwable t) 
       {
  -	log(msg, t, Logger.ERROR);
  +	log(msg, t, ERROR);
       }
       
       /**
  @@ -198,88 +188,87 @@
        **/
       public void log(String msg, Throwable t, int level)
       {
  -	if (prefix != null) {
  -	    // tuneme
  -	    msg = prefix + ": " + msg;
  -	}
  -	
  -	
  -	// activate logname fetch if necessary
  -	if (logger == null) {
  -	    if (logname != null)
  -		logger = Logger.getLogger(logname);
  -	}
  -	
  -	// if all else fails, use default logger (writes to default sink)
  -	Logger loggerTemp = logger;
  -	if (loggerTemp == null) {
  -	    loggerTemp = Logger.defaultLogger;
  -	}
  -	loggerTemp.log(msg, t, level);
  +	log( prefix, msg, t, level );
       }
   
  +    /** 
  +     */
  +    public void log( String prefix, String msg, Throwable t, int level ) {
  +	proxy.log( prefix, msg, t, level );
  +    }
  +    
  +    /** Flush any buffers.
  +     *  Override if needed.
  +     */
       public void flush() {
  -	if( logger!=null )
  -	    logger.flush();
  +	proxy.flush();
       }
   
  -    public int getLevel() {
  -	if( logger==null ) return Log.DEBUG;
  -	return logger.getVerbosityLevel();
  +    public void close() {
  +	proxy.close();
       }
  -    
  -    // -------------------- Extra configuration stuff --------------------
  -    // The real logger object ( that knows to write to
  -    // files, optimizations, etc)
  -    private Logger logger;
   
  -    public Logger getLogger() {
  -	return logger;
  +    /** The configured logging level for this channel
  +     */
  +    public int getLevel() {
  +	return proxy.getLevel();
       }
  +
  +    // -------------------- Management --------------------
  +
  +    // No getter for the log manager ( user code shouldn't be
  +    // able to control the logger )
       
  -    /**
  -     * Set a logger explicitly.  Also resets the logname property to
  -     * match that of the given log.
  +    /** Used by the embeding application ( tomcat ) to manage
  +     *  the logging.
        *
  -     * <p>(Note that setLogger(null) will not necessarily redirect log
  -     * output to System.out; if there is a logger named logname it
  -     * will fall back to using it, or trying to.)
  -     **/
  -    public void setLogger(Logger logger) {
  -	if (logger != null)
  -	    setLogname(logger.getName());
  -	this.logger = logger;
  -    }
  -    
  -    /**
  -     * Set the logger by name.  Will throw away current idea of what
  -     * its logger is, and next time it's asked, will locate the global
  -     * Logger object if the given name.
  -     **/	
  -    public void setLogname(String logname) {
  -	logger = null;	// prepare to locate a new logger
  -	this.logname = logname;
  +     *  Initially, the Log is not managed, and the default
  +     *  manager is used. The application can find what loggers
  +     *  have been created from the default LogManager, and 
  +     *  provide a special manager implemetation.
  +     */
  +    public static void setLogManager( LogManager lm ) {
  +	// can be changed only once - so that user
  +	// code can't change the log manager in running servers
  +	if( logManager.getClass() == LogManager.class ) {
  +	    logManager=lm;
  +	}
       }
  -    
  -    /**
  -     * Set the prefix string to be prepended to each message
  -     **/
  -    public void setLogPrefix(String prefix) {
  -	this.prefix = prefix;
  +
  +    public void setProxy( LogManager lm, LogHandler l ) {
  +	// only the manager can change the proxy
  +	if( lm!= logManager ) return;
  +	proxy=l;
       }
  +
  +    /** Security notes:
  +
  +    Log acts as a facade to an actual logger ( which has setters, etc).
       
  -    // 	/**
  -    // 	 * Set a "proxy" Log -- whatever that one says its
  -    // 	 * Logger is, use it
  -    // 	 **/
  -    // 	public void setProxy(Log helper) {
  -    // 	    this.proxy = helper;
  -    // 	}
  +    The "manager" ( embeding application ) can set the handler, and
  +    edit/modify all the properties at run time.
  +
  +    Applications can log if they get a Log instance. From Log there is
  +    no way to get an instance of the LogHandler or LogManager.
  +
  +    LogManager controls access to the Log channels - a 1.2 implementation
  +    would check for LogPermissions ( or other mechanisms - like
  +    information about the current thread, etc ) to determine if the
  +    code can get a Log.
       
  +    The "managing application" ( tomcat for example ) can control
  +    any aspect of the logging and change the actual logging
  +    implementation behind the scenes.
  +
  +    One typical usage is that various components will use Log.getLog()
  +    at various moments. The "manager" ( tomcat ) will initialize the
  +    logging system by setting a LogManager implementation ( which
  +    can't be changed by user code after that ). It can then set the
  +    actual implementation of the logger at any time. ( or provide
  +    access to trusted code to it ).
  +
  +    Please review.
  +    */
       
  -    // ???
  -    // 	public Log getLog() {
  -    // 	    return this;
  -    // 	}
       
  -    }    
  +}    
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/util/log/LogHandler.java
  
  Index: LogHandler.java
  ===================================================================
  /*
   * ====================================================================
   * 
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */ 
  package org.apache.tomcat.util.log;
  
  import org.apache.tomcat.util.log.*;
  import java.io.Writer;
  import java.io.PrintWriter;
  import java.io.FileWriter;
  import java.io.File;
  import java.io.OutputStreamWriter;
  import java.io.IOException;
  import java.io.StringWriter;
  
  import java.util.*;
  
  
  /**
   * Log destination ( or channel ). This is the base class that will be
   * extended by log handlers - tomcat uses util.qlog.QueueLogger,
   * in future we'll use log4j or java.util.logger adapters.
   *
   * The base class writes to a (default) writer, and it can
   * be used for very simple logging.
   * 
   * @author Anil Vijendran (akv@eng.sun.com)
   * @author Alex Chaffee (alex@jguru.com)
   * @author Ignacio J. Ortega (nacho@siapi.es)
   * @author Costin Manolache
   */
  public  class LogHandler {
  
      protected PrintWriter sink = defaultSink;
      protected int level = Log.WARNING;
  
      
      /**
       * Prints log message and stack trace.
       * This method should be overriden by real logger implementations
       *
       * @param	prefix		optional prefix. 
       * @param	message		the message to log. 
       * @param	t		the exception that was thrown.
       * @param	verbosityLevel	what type of message is this?
       * 				(WARNING/DEBUG/INFO etc)
       */
      public void log(String prefix, String msg, Throwable t,
  		    int verbosityLevel)
      {
  	if( sink==null ) return;
  	// default implementation ( in case no real logging is set up  )
  	if( verbosityLevel > this.level ) return;
  	
  	if (prefix != null) 
  	    sink.println(prefix + ": " + msg );
  	else 
  	    sink.println(  msg );
  	
  	if( t!=null )
  	    t.printStackTrace( sink );
      }
  
      /**
       * Flush the log. 
       */
      public void flush() {
  	if( sink!=null)
  	    sink.flush();
      }
  
  
      /**
       * Close the log. 
       */
      public synchronized void close() {
  	this.sink = null;
      }
      
      /**
       * Set the verbosity level for this logger. This controls how the
       * logs will be filtered. 
       *
       * @param	level		one of the verbosity level codes. 
       */
      public void setLevel(int level) {
  	this.level = level;
      }
      
      /**
       * Get the current verbosity level.
       */
      public int getLevel() {
  	return this.level;
      }
  
  
      // -------------------- Default sink
      
      protected static PrintWriter defaultSink =
  	new PrintWriter( new OutputStreamWriter(System.err));
  
      /**
       * Set the default output stream that is used by all logging
       * channels.
       *
       * @param	w		the default output stream.
       */
      public static void setDefaultSink(Writer w) {
  	if( w instanceof PrintWriter )
  	    defaultSink=(PrintWriter)w;
  	else 
  	    defaultSink = new PrintWriter(w);
      }
  
      // -------------------- General purpose utilitiy --------------------
  
      
  
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/util/log/LogManager.java
  
  Index: LogManager.java
  ===================================================================
  /*
   * ====================================================================
   * 
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */ 
  package org.apache.tomcat.util.log;
  
  import java.io.*;
  import java.lang.reflect.*;
  import java.util.*;
  
  
  /**
   * Allows the control the log properties at runtime.
   * Normal applications will just use Log, without having to
   * deal with the way the log is configured or managed.
   *
   *
   * @author Alex Chaffee [alex@jguru.com]
   * @author Costin Manolache
   **/
  public class LogManager {
  
      static LogHandler defaultChannel=null;
      
      protected Hashtable loggers=new Hashtable();
      protected Hashtable channels=new Hashtable();
  
      public static void setDefault( LogHandler l ) {
  	if( defaultChannel==null)
  	    defaultChannel=l;
      }
  
      public void addChannel( String name, LogHandler logH ) {
  	if(name==null) name="";
  
  	channels.put( name, logH );
      }
      
      /** Default method to create a log facade.
       */
      public Log getLog( String channel, String prefix,
  			  Object owner ) {
  	if( prefix==null && owner!=null ) {
  	    String cname = owner.getClass().getName();
  	    prefix = cname.substring( cname.lastIndexOf(".") +1);
  	}
  
  	// user-level loggers
  	Log log=new Log( channel, prefix, owner );
  	loggers.put( channel + ":" + prefix, log );
  
  	// channels 
  	LogHandler proxy=(LogHandler)channels.get(channel);
  	if( proxy!= null ) {
  	    log.setProxy( this, proxy );
  	} else {
  	    if( defaultChannel!=null )
  		log.setProxy( this, defaultChannel );
  	}
  
  	return log;
      }
  
  
  }    
  
  
  
  1.9       +10 -10    jakarta-tomcat/src/share/org/apache/tomcat/util/net/PoolTcpEndpoint.java
  
  Index: PoolTcpEndpoint.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/net/PoolTcpEndpoint.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- PoolTcpEndpoint.java	2001/02/20 03:14:12	1.8
  +++ PoolTcpEndpoint.java	2001/03/02 04:11:48	1.9
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/net/PoolTcpEndpoint.java,v 1.8 2001/02/20 03:14:12 costin Exp $
  - * $Revision: 1.8 $
  - * $Date: 2001/02/20 03:14:12 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/net/PoolTcpEndpoint.java,v 1.9 2001/03/02 04:11:48 costin Exp $
  + * $Revision: 1.9 $
  + * $Date: 2001/03/02 04:11:48 $
    *
    * ====================================================================
    *
  @@ -119,7 +119,7 @@
       static final int debug=0;
   
       ThreadPool tp;
  -    protected Log _log=new Log("tc_log");
  +    protected Log _log=Log.getLog("tc/PoolTcpEndpoint", "PoolTcpEndpoint");
       
       public PoolTcpEndpoint() {
   	//	super("tc_log");	// initialize default logger
  @@ -253,7 +253,7 @@
       	    listener = new TcpWorkerThread(this);
               tp.runIt(listener);
           } else {
  -	    log("XXX Error - need pool !", null, Logger.ERROR);
  +	    log("XXX Error - need pool !", null, Log.ERROR);
   	}
       }
   
  @@ -306,7 +306,7 @@
       	    if (running != false) {
   		String msg = sm.getString("endpoint.err.nonfatal",
   					  serverSocket, e);
  -		log(msg, e, Logger.INFORMATION);
  +		log(msg, e, Log.INFORMATION);
       	    }
   
       	} 
  @@ -319,11 +319,11 @@
               // on an AccessControlException.
   	    if( e.getClass().getName().equals("java.security.AccessControlException") ) {
   		String msg = "Socket: "+ serverSocket + " AccessControlException: " + e.toString();
  -		log(msg, Logger.ERROR);
  +		log(msg, Log.ERROR);
   	    } else {
   		String msg = sm.getString("endpoint.err.fatal",
   					serverSocket, e);    
  -		log(msg, e, Logger.ERROR);
  +		log(msg, e, Log.ERROR);
   		stopEndpoint();	// safe to call this from inside thread pool?
   	    }
       	}
  @@ -333,12 +333,12 @@
   
       public void log(String msg) 
       {
  -	_log.log(msg, null, Logger.INFORMATION);
  +	_log.log(msg, null, Log.INFORMATION);
       }
       
       public void log(String msg, Throwable t) 
       {
  -	_log.log(msg, t, Logger.ERROR);
  +	_log.log(msg, t, Log.ERROR);
       }
   
       public void log(String msg, int level) 
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/util/qlog/FastDateFormat.java
  
  Index: FastDateFormat.java
  ===================================================================
  /*
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * Original code Copyright 2000 Quadcap Software: 
   * This software may be freely redistributed in source or binary form
   * for any purpose.
   *
   */
  
  package org.apache.tomcat.util.qlog;
  
  import java.util.Date;
  
  import java.text.DateFormat;
  import java.text.FieldPosition;
  import java.text.ParsePosition;
  import java.text.SimpleDateFormat;
  
  /**
   * Fast date formatter that caches recently formatted date information
   * and uses it to avoid too-frequent calls to the underlying
   * formatter.  Note: breaks fieldPosition param of format(Date,
   * StringBuffer, FieldPosition).  If you care about the field
   * position, call the underlying DateFormat directly.
   *
   * @author Stan Bailes
   * @author Alex Chaffee
   **/
  public class FastDateFormat extends DateFormat {
      DateFormat    df;
      long          lastSec = -1;
      StringBuffer  sb      = new StringBuffer();
      FieldPosition fp      = new FieldPosition(DateFormat.MILLISECOND_FIELD);
      
      public FastDateFormat(DateFormat df) {
          this.df = df;
      }
  
      public Date parse(String text, ParsePosition pos) {
  	return df.parse(text, pos);
      }
  
      /**
       * Note: breaks functionality of fieldPosition param. Also:
       * there's a bug in SimpleDateFormat with "S" and "SS", use "SSS"
       * instead if you want a msec field.
       **/
      public StringBuffer format(Date date, StringBuffer toAppendTo,
  			       FieldPosition fieldPosition) {
          long dt = date.getTime();
          long ds = dt / 1000;
          if (ds != lastSec) {
              sb.setLength(0);
              df.format(date, sb, fp);
              lastSec = ds;
          } else {
  	    // munge current msec into existing string
              int ms = (int)(dt % 1000);
              int pos = fp.getEndIndex();
  	    int begin = fp.getBeginIndex();
  	    if (pos > 0) {
  		if (pos > begin)
  		    sb.setCharAt(--pos, Character.forDigit(ms % 10, 10));
  		ms /= 10;
  		if (pos > begin)
  		    sb.setCharAt(--pos, Character.forDigit(ms % 10, 10));
  		ms /= 10;
  		if (pos > begin)
  		    sb.setCharAt(--pos, Character.forDigit(ms % 10, 10));
  	    }
          }
  	toAppendTo.append(sb.toString());
  	return toAppendTo;
      }
  
      /*
      public static void main(String[] args) {
  	String format = "yyyy-MM-dd HH:mm:ss.SSS";
  	if (args.length > 0)
  	    format = args[0];
          SimpleDateFormat sdf = new SimpleDateFormat(format);
          FastDateFormat fdf = new FastDateFormat(sdf);
          Date d = new Date();
  
  	d.setTime(1); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
  	d.setTime(20); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
  	d.setTime(500); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
  	d.setTime(543); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
  	d.setTime(999); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
  	d.setTime(1050); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
  	d.setTime(2543); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
  	d.setTime(12345); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
  	d.setTime(12340); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
  	
          final int reps = 100000;
          {
              long start = System.currentTimeMillis();
              for (int i = 0; i < reps; i++) {
                  d.setTime(System.currentTimeMillis());
                  fdf.format(d);
              }
              long elap = System.currentTimeMillis() - start;
              System.out.println("fast: " + elap + " elapsed");
  	    System.out.println(fdf.format(d));
          }
          {
              long start = System.currentTimeMillis();
              for (int i = 0; i < reps; i++) {
                  d.setTime(System.currentTimeMillis());
                  sdf.format(d);
              }
              long elap = System.currentTimeMillis() - start;	    
              System.out.println("slow: " + elap + " elapsed");
  	    System.out.println(sdf.format(d));
          }
      }
      */
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/util/qlog/LogEntry.java
  
  Index: LogEntry.java
  ===================================================================
  /*
   * ====================================================================
   * 
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */ 
  package org.apache.tomcat.util.qlog;
  
  import java.io.Writer;
  import java.io.StringWriter;
  import java.io.PrintWriter;
  
  import java.util.Date;
  
  /**
   * This is an entry that is created in response to every
   * Logger.log(...) call.
   *
   * @author Anil V (akv@eng.sun.com)
   * @since  Tomcat 3.1
   */
  public final  class LogEntry {
      String logName;
      long date=0;
      String message;
      Throwable t;
      QueueLogger l;
      
      LogEntry(QueueLogger l, long date, String message, Throwable t) {
  	this.date = date;
  	this.message = message;
  	this.t = t;
  	this.l=l;
      }
      
      LogEntry( QueueLogger l, String message, Throwable t) {
  	this.message = message;
  	this.t = t;
  	this.l=l;
      }
  
      // XXX should move to LogFormat !!!
      public void print( StringBuffer outSB) {
  	if (date!=0) {
  	    l.formatTimestamp( date, outSB );
  	    outSB.append(" - ");
  	}
  	
  	if (message != null) 
  	    outSB.append(message);
  	
  	if (t != null) {
  	    outSB.append(" - ");
  	    outSB.append(l.throwableToString( t ));
  	}
      }
      
      
  
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/util/qlog/Logger.java
  
  Index: Logger.java
  ===================================================================
  /*
   * ====================================================================
   * 
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */ 
  package org.apache.tomcat.util.qlog;
  
  import org.apache.tomcat.util.log.*;
  import java.io.Writer;
  import java.io.PrintWriter;
  import java.io.FileWriter;
  import java.io.File;
  import java.io.OutputStreamWriter;
  import java.io.IOException;
  import java.io.StringWriter;
  import java.lang.reflect.*;
  
  import java.util.*;
  import java.text.DateFormat;
  import java.text.SimpleDateFormat;
  
  /**
   * Interface for a logging object. A logging object provides mechanism
   * for logging errors and messages that are of interest to someone who
   * is trying to monitor the system.
   * 
   * @author Anil Vijendran (akv@eng.sun.com)
   * @author Alex Chaffee (alex@jguru.com)
   * @author Ignacio J. Ortega (nacho@siapi.es)
   * @since  Tomcat 3.1
   */
  public abstract class Logger extends LogHandler {
      // -------------------- Internal fields --------------------
  
      protected static Writer defaultSink = new OutputStreamWriter(System.err);
  
      protected long day;
      
      // Usefull for subclasses
      private static final String separator =
  	System.getProperty("line.separator", "\n");
      public static final char[] NEWLINE=separator.toCharArray();
  
      /**
       * Set the default output stream that is used by all logging
       * channels.
       *
       * @param	w		the default output stream.
       */
      public static void setDefaultSink(Writer w) {
  	defaultSink = w;
      }
  
  
      // ----- instance (non-static) content -----
      
      protected boolean custom = true;
      protected Writer sink = defaultSink;
      protected String path;
      
      /**
       * Should we timestamp this log at all?
       **/
      protected boolean timestamp = true;
  
      /**
       * true = The timestamp format is raw msec-since-epoch <br>
       * false = The timestamp format is a custom string to pass to
       *         SimpleDateFormat
       **/
      protected boolean timestampRaw = false;
  
      /**
       * The timestamp format string, default is "yyyy-MM-dd hh:mm:ss"
       **/
      protected String timestampFormat = "yyyy-MM-dd HH:mm:ss";
  
      protected DateFormat timestampFormatter
  	= new FastDateFormat(new SimpleDateFormat(timestampFormat));
  
      /**
       * Prints log message and stack trace.
       *
       * @param	message		the message to log. 
       * @param	t		the exception that was thrown.
       * @param	verbosityLevel	what type of message is this?
       * 				(WARNING/DEBUG/INFO etc)
       */
      public final void log(String prefix, String message, Throwable t,
  			  int verbosityLevel)
      {
  	if (prefix != null) {
  	    message = prefix + ": " + message;
  	}
  
  	if (verbosityLevel <= getVerbosityLevel()) {
              // check wheter we are logging to a file
              if (path!= null){
                  // If the date has changed, switch log files
                  if (day!=getDay(System.currentTimeMillis())) {
                      synchronized (this) {
                          close();
                          open();
                      }
                  }
              }
  	    realLog(message,t);
  	}
      }
  
      /** 
       * Subclasses implement these methods which are called by the
       * log(..) methods internally. 
       *
       * @param	message		the message to log. 
       * @param	t		the exception that was thrown.
       */
      protected abstract void realLog(String message, Throwable t);
  
      /**
       * Set the path name for the log output file.
       *
       * @param	path		The path to the log file.
       */
      public void setPath(String path) {
          if (File.separatorChar == '/')
              this.path = path.replace('\\', '/');
          else if (File.separatorChar == '\\')
              this.path = path.replace('/', '\\');
      }
  
      public String getPath() {
  	return path;
      }
  
      /** Open the log - will create the log file and all the parent directories.
       *  You must open the logger before use, or it will write to System.err
       */
      public void open() {
  	if (path == null)
              return;
  	// use default sink == System.err
          long date=System.currentTimeMillis();
          day=getDay(date);
  	try {
  	    File file = new File(path);
              String logName=file.getParent()+File.separator+
  		getDatePrefix(date,file.getName());
              file=new File(logName);
  	    if (!file.exists())
  		new File(file.getParent()).mkdirs();
  	    this.sink = new FileWriter(logName);
  	} catch (IOException ex) {
  	    System.err.print("Unable to open log file: "+path+"! ");
  	    System.err.println(" Using stderr as the default.");
  	    this.sink = defaultSink;
  	}
      }
  
      
  
      /**
       * Set the verbosity level for this logger. This controls how the
       * logs will be filtered. 
       *
       * @param	level		one of the verbosity level strings. 
       */
      public void setVerbosityLevel(String level) {
  	if ("warning".equalsIgnoreCase(level))
  	    this.level = Log.WARNING;
  	else if ("fatal".equalsIgnoreCase(level))
  	    this.level = Log.FATAL;
  	else if ("error".equalsIgnoreCase(level))
  	    this.level = Log.ERROR;
  	else if ("information".equalsIgnoreCase(level))
  	    this.level = Log.INFORMATION;
  	else if ("debug".equalsIgnoreCase(level))
  	    this.level = Log.DEBUG;
      }
  
      /**
       * Set the verbosity level for this logger. This controls how the
       * logs will be filtered. 
       *
       * @param	level		one of the verbosity level codes. 
       */
      public void setVerbosityLevel(int level) {
  	this.level = level;
      }
      
      /**
       * Get the current verbosity level.
       */
      public int getVerbosityLevel() {
  	return this.level;
      }
  
      /**
       * Get the current verbosity level.
       */
      public int getLevel() {
  	return this.level;
      }
  
      /**
       * Do we need to time stamp this or not?
       *
       * @param	value		"yes/no" or "true/false"
       */
      public void setTimestamp(String value) {
  	if ("true".equalsIgnoreCase(value) ||
  	    "yes".equalsIgnoreCase(value))
  	    timestamp = true;
  	else if ("false".equalsIgnoreCase(value) ||
  		 "no".equalsIgnoreCase(value))
  	    timestamp = false;
      }
  
      public  boolean isTimestamp() {
  	return timestamp;
      }
  
      /**
       * If we are timestamping at all, what format do we use to print
       * the timestamp? See java.text.SimpleDateFormat.
       *
       * Default = "yyyy-MM-dd hh:mm:ss". Special case: "msec" => raw
       * number of msec since epoch, very efficient but not
       * user-friendly
       **/
      public void setTimestampFormat(String value)
      {
  	if (value.equalsIgnoreCase("msec"))
  	    timestampRaw = true;
  	else {
  	    timestampRaw = false;
  	    timestampFormat = value;
  	    timestampFormatter =
  		new FastDateFormat(new SimpleDateFormat(timestampFormat));
  	}
      }
      
      public String getTimestampFormat()
      {
  	if (timestampRaw)
  	    return "msec";
  	else
  	    return timestampFormat;
      }
  
      protected String formatTimestamp(long msec) {
  	StringBuffer buf = new StringBuffer();
  	formatTimestamp(msec, buf);
  	return buf.toString();
      }
  
      // dummy variable to make SimpleDateFormat work right
      private static java.text.FieldPosition position =
  	new java.text.FieldPosition(DateFormat.YEAR_FIELD);
  
      protected void formatTimestamp(long msec, StringBuffer buf) {
  	if (!timestamp)
  	    return;
  	else if (timestampRaw) {
  	    buf.append(Long.toString(msec));
  	    return;
  	}
  	else {
  	    Date d = new Date(msec);
  	    timestampFormatter.format(d, buf, position);
  	    return;
  	}
      }
  
      // ----- utility methods; -----
      static final String START_FORMAT="${";
      static final String END_FORMAT="}";
  
      private String getDatePrefix(long millis,String format) {
          try{
              int pos=format.indexOf(Logger.START_FORMAT);
              int lpos=format.lastIndexOf(Logger.END_FORMAT);
              if( pos != -1 && lpos != -1){
                  String f="'"+format.substring(0,pos)+"'"
                          +format.substring(pos+2,lpos)
                          +"'"+format.substring(lpos+1)+"'";
                  SimpleDateFormat sdf=new SimpleDateFormat(f);
                  return sdf.format(new Date(millis));
              }
          }catch(Exception ex){
          }
          return format;
      }
  
      private long getDay(long millis){
          return (millis+TimeZone.getDefault().getRawOffset()) /
  	    ( 24*60*60*1000 );
      }
  
      // -------------------- Public Utilities --------------------
      
      /**
       * Converts a Throwable to a printable stack trace, including the
       * nested root cause for a ServletException or TomcatException if
       * applicable
       * TODO: JDBCException too
       *
       * @param t any Throwable, or ServletException, or null
       **/
      public static String throwableToString( Throwable t ) {
  	// we could use a StringManager here to get the
  	// localized translation of "Root cause:" , but
  	// since it's going into a log, no user will see
  	// it, and it's desirable that the log file is
  	// predictable, so just use English
  	return throwableToString( t, "Root cause:" );
      }
  
      public static final int MAX_THROWABLE_DEPTH=3;
  
      /**
       * Converts a Throwable to a printable stack trace, including the
       * nested root cause for a ServletException or TomcatException or
       * SQLException if applicable
       *
       * @param t any Throwable, or ServletException, or null
       * @param rootcause localized string equivalent of "Root Cause"
       **/
      public static String throwableToString( Throwable t, String rootcause ) {
  	if (rootcause == null)
  	    rootcause = "Root Cause:";
  	StringWriter sw = new StringWriter();
  	PrintWriter w = new PrintWriter(sw);
  	printThrowable(w, t, rootcause, MAX_THROWABLE_DEPTH);
  	w.flush();
  	return sw.toString();
      }
  
      private static Object[] emptyObjectArray=new Object[0];
  
      private static void printThrowable(PrintWriter w, Throwable t,
  				       String rootcause, int depth )
      {
  
  	if (t != null) {
  	    // XXX XXX XXX Something seems wrong - DOS, permissions. Need to
  	    // check.
  	    t.printStackTrace(w);
  
  	    // Find chained exception using few general patterns
  	    
  	    Class tC=t.getClass();
  	    Method mA[]= tC.getMethods();
  	    Method nextThrowableMethod=null;
  	    for( int i=0; i< mA.length ; i++  ) {
  		if( "getRootCause".equals( mA[i].getName() )
  		    || "getNextException".equals( mA[i].getName() )
  		    || "getException".equals( mA[i].getName() )) {
  		    // check param types
  		    Class params[]=mA[i].getParameterTypes();
  		    if( params==null || params.length==0 ) {
  			nextThrowableMethod=mA[i];
  			break;
  		    }
  		}
  	    }
  
  	    if( nextThrowableMethod != null ) {
  		try {
  		    Throwable nextT=(Throwable)nextThrowableMethod.
  			invoke( t , emptyObjectArray );
  		    if( nextT != null ) {
  			w.println(rootcause);
  			if( depth > 0 ) {
  			    printThrowable(w, nextT, rootcause, depth-1);
  			}
  		    }
  		} catch( Exception ex ) {
  		    // ignore
  		}
  	    }
  	}
      }
      
  //     /**
  //      * General purpose nasty hack to determine if an exception can be
  //      * safely ignored -- specifically, if it's an IOException or
  //      * SocketException that is thrown in the normal course of a socket
  //      * closing halfway through a connection, or if it's a weird
  //      * unknown type of exception.  This is an intractable problem, and
  //      * this is a bad solution, but at least it's centralized.
  //      **/
  //     public static boolean canIgnore(Throwable t) {
  // 	String msg = t.getMessage();
  // 	if (t instanceof java.io.InterruptedIOException) {
  // 	    return true;
  // 	}
  // 	else if (t instanceof java.io.IOException) {
  // 	    // Streams throw Broken Pipe exceptions if their
  // 	    // underlying sockets close
  // 	    if( "Broken pipe".equals(msg))
  // 		return true;
  // 	}
  // 	else if (t instanceof java.net.SocketException) {
  // 	    // TCP stacks can throw SocketExceptions when the client
  // 	    // disconnects.  We don't want this to shut down the
  // 	    // endpoint, so ignore it. Is there a more robust
  // 	    // solution?  Should we compare the message string to
  // 	    // "Connection reset by peer"?
  // 	    return true;
  // 	}
  // 	return false;
  //     }
  
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/util/qlog/QueueLogger.java
  
  Index: QueueLogger.java
  ===================================================================
  /*
   * ====================================================================
   * 
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */ 
  package org.apache.tomcat.util.qlog;
  
  import java.io.Writer;
  import java.io.StringWriter;
  import java.io.PrintWriter;
  
  import java.util.Date;
  
  import org.apache.tomcat.util.collections.Queue;
  
  /**
   * A real implementation of the Logger abstraction.
   * It uses a log queue, so that the caller will not
   * have to wait.
   *
   * @author Anil V (akv@eng.sun.com)
   * @since  Tomcat 3.1
   */
  public class QueueLogger extends Logger {
      /**
       * Just one daemon and one queue for all Logger instances.. 
       */
      static LogDaemon logDaemon = null;
      static Queue     logQueue  = null;
  
      public QueueLogger() {
  	if (logDaemon == null || logQueue == null) {
  	    logQueue = new Queue();
  	    logDaemon = new LogDaemon(logQueue);
  	    logDaemon.start();
  	}
      }
      
      /**
       * Adds a log message and stack trace to the queue and returns
       * immediately. The logger daemon thread will pick it up later and
       * actually print it out. 
       *
       * @param	message		the message to log. 
       * @param	t		the exception that was thrown.
       */
      final protected void realLog(String message, Throwable t) {
  	if( timestamp )
  	    logQueue.put(new LogEntry(this,
  				      System.currentTimeMillis(),
  				      message, t));
  	else
  	    logQueue.put(new LogEntry(this,
  				      message, t));
      }
      
      /**
       * Flush the log. In a separate thread, no wait for the caller.
       */
      public void flush() {
  	logDaemon.flush();
      }
  
  }
  
  /**
   * The daemon thread that looks in a queue and if it is not empty
   * writes out everything in the queue to the sink.
   */
  final class LogDaemon extends Thread {
      private Queue logQueue;
      
      LogDaemon(Queue logQueue) {
  	this.logQueue = logQueue;
  	setDaemon(true);
      }
  	
      private static final char[] NEWLINE=Logger.NEWLINE;
      
      // There is only one thread, so we can reuse this
      char outBuffer[]=new char[512]; // resize
      
      // NEVER call toString() on StringBuffer!!!!!
      StringBuffer outSB = new StringBuffer();
      
      
      private void emptyQueue() {
  	do {
  	    LogEntry logEntry =
  		(LogEntry) logQueue.pull();
  	    QueueLogger tl=logEntry.l;
  		Writer writer=tl.sink;
  		if (writer != null) {
  		    try {
  			outSB.setLength(0);
  			
  			logEntry.print( outSB );
  			outSB.append( NEWLINE );
  			
  			int len=outSB.length();
  			if( len > outBuffer.length ) {
  			    outBuffer=new char[len];
  			}
  			outSB.getChars(0, len, outBuffer, 0);
  
  			writer.write( outBuffer, 0, len );	    
  			writer.flush();
  		    } catch (Exception ex) { // IOException
  			ex.printStackTrace(); // nowhere else to write it
  		    }
  		}
  	} while (!LogDaemon.this.logQueue.isEmpty());
      }
  
      public void run() {
  	while (true) {
  	    emptyQueue();
  	}
      }
      
      /** Flush the queue - in a separate thread, so that
  	caller doesn't have to wait
      */
      public void flush() {
  	Thread workerThread = new Thread(flusher);
  	workerThread.start();
      }
      
      Runnable flusher = new Runnable() {
  	    public void run() {
  		emptyQueue();
  	    }
  	};
  }
  
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/util/qlog/package.html
  
  Index: package.html
  ===================================================================
  A very efficient and small implementation of LogHandler.
  <p>
  The code is good, but needs a bit of cleaning.
  
  
  1.3       +6 -6      jakarta-tomcat/src/share/org/apache/tomcat/util/threads/ThreadPool.java
  
  Index: ThreadPool.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/threads/ThreadPool.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ThreadPool.java	2000/09/29 07:01:55	1.2
  +++ ThreadPool.java	2001/03/02 04:11:52	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/threads/ThreadPool.java,v 1.2 2000/09/29 07:01:55 costin Exp $
  - * $Revision: 1.2 $
  - * $Date: 2000/09/29 07:01:55 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/threads/ThreadPool.java,v 1.3 2001/03/02 04:11:52 costin Exp $
  + * $Revision: 1.3 $
  + * $Date: 2001/03/02 04:11:52 $
    *
    * ====================================================================
    *
  @@ -130,7 +130,7 @@
       /**
        * Helper object for logging
        **/
  -    Log loghelper = new Log("tc_log", "ThreadPool");
  +    Log loghelper = Log.getLog("tc/ThreadPool", "ThreadPool");
       
       public ThreadPool() {
           maxThreads      = MAX_THREADS;
  @@ -250,7 +250,7 @@
   		     * Do nothing... The show must go on, we are shutting 
   		     * down the pool and nothing should stop that.
   		     */
  -		    loghelper.log("Ignored exception while shutting down thread pool", t, Logger.ERROR);
  +		    loghelper.log("Ignored exception while shutting down thread pool", t, Log.ERROR);
                   }
               }
               currentThreadsBusy = currentThreadCount = 0;
  @@ -399,7 +399,7 @@
                       p.checkSpareControllers();
   
                   } catch(Throwable t) {
  -		    loghelper.log("Unexpected exception", t, Logger.ERROR);
  +		    loghelper.log("Unexpected exception", t, Log.ERROR);
                   }
               }
           }