Return-Path: Delivered-To: apmail-jakarta-tomcat-dev-archive@apache.org Received: (qmail 72760 invoked from network); 22 Jul 2002 16:33:23 -0000 Received: from unknown (HELO nagoya.betaversion.org) (192.18.49.131) by daedalus.apache.org with SMTP; 22 Jul 2002 16:33:23 -0000 Received: (qmail 17087 invoked by uid 97); 22 Jul 2002 16:33:06 -0000 Delivered-To: qmlist-jakarta-archive-tomcat-dev@jakarta.apache.org Received: (qmail 16963 invoked by uid 97); 22 Jul 2002 16:33:06 -0000 Mailing-List: contact tomcat-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Tomcat Developers List" Reply-To: "Tomcat Developers List" Delivered-To: mailing list tomcat-dev@jakarta.apache.org Received: (qmail 16882 invoked by uid 98); 22 Jul 2002 16:33:05 -0000 X-Antivirus: nagoya (v4198 created Apr 24 2002) Subject: Re: JDK 1.4 Logging From: Bob Herrmann To: Tomcat Developers List In-Reply-To: <3D3C32BA.4060104@sun.com> References: <1027349462.22700.18.camel@dhcp-70-230> <3D3C32BA.4060104@sun.com> Content-Type: text/plain Content-Transfer-Encoding: 7bit X-Mailer: Ximian Evolution 1.0.8 Date: 22 Jul 2002 12:35:48 -0400 Message-Id: <1027355748.23504.39.camel@dhcp-70-230> Mime-Version: 1.0 X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N Humm... How about this instead (not that I am lazy)? $ cvs diff -u catalina/build.xml Index: catalina/build.xml =================================================================== RCS file: /home/cvspublic/jakarta-tomcat-4.0/catalina/build.xml,v retrieving revision 1.124 diff -u -r1.124 build.xml --- catalina/build.xml 29 Jun 2002 01:00:04 -0000 1.124 +++ catalina/build.xml 22 Jul 2002 16:31:07 -0000 @@ -801,6 +801,8 @@ unless="jdk.1.3.present"/> + Bob, > > This is a useful piece of code. However, your patch can't go into Tomcat > as it will only compile with JDK 1.4. The standard builds of Tomcat that > are downloadable from the jakarta.apache.org are built using JDK 1.3 and > should be run without crashing Tomcat on JDK 1.2. > > So, if you would like this in Tomcat (and I think it would be a nice > optional logger implementation), I think that you need to do the following: > > 1. Remove all of the following import statements and replace them with > reflection calls so that the JDK 1.3 compiler can compile this class: > > import java.util.logging.Logger; > import java.util.logging.Level; > import java.util.logging.Formatter; > import java.util.logging.Handler; > import java.util.logging.LogRecord; > > 2. Catch any ClassNotFound and MethodNotFound exceptions that will occur > when the code is run on JDK 1.2 or 1.3. > > Patrick > > > > > Bob Herrmann wrote: > > Hi. I am trying to get Tomcat to log to JDK1.4's logging. > > > > I tried implementing a "o.a.c.logging.Logger" subclass that forwarded > > calls to commons-logging Log. This was unsatisfying because the > > commons-logger unrolls the stack and logs the "class.method" of my > > logger, not my logger's caller. > > > > I was tempted to change the commons-logger to allow for specifying > > a class and method on all its methods, but that would be a large > > change the commons-logger (involving changes and decisions about > > how this new information should be pushed down and handled with > > the other loggers it supports.) There is also some issues mapping > > tomcat verbosity levels, to common-logger log levels and then to JDK > > Logger levels. > > > > So I punted and implemented the code below. It is a > > "o.a.c.logging.Logger" which writes directly to JDK 1.4 Logging. > > It allowed me to unroll the stack in a way that fits well with > > tomcat (ignoring stack frames calling with method log() or method > > internalLog() which are uninteresting.) And allowed me to map > > verbosity to JDK Levels. > > > > Cheers, > > -bob > > > > > > > > > > ------------------------------------------------------------------------ > > > > /* > > * $Header: $ > > * $Revision: $ > > * $Date: $ > > * > > * ==================================================================== > > * > > * 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 > > * . > > * > > * [Additional notices, if required by prior licensing conditions] > > * > > */ > > > > > > package org.apache.catalina.logger; > > > > import java.sql.Timestamp; > > > > import org.apache.catalina.Lifecycle; > > import org.apache.catalina.LifecycleEvent; > > import org.apache.catalina.LifecycleException; > > import org.apache.catalina.LifecycleListener; > > import org.apache.catalina.util.LifecycleSupport; > > import org.apache.catalina.util.StringManager; > > > > import java.util.logging.Logger; > > import java.util.logging.Level; > > import java.util.logging.Formatter; > > import java.util.logging.Handler; > > import java.util.logging.LogRecord; > > > > > > /** > > * Implementation of Logger that sends log messages to the > > * Jdk logger > > * > > * @version $Revision: $ $Date: $ > > */ > > > > public class JdkLogger > > extends LoggerBase > > implements Lifecycle { > > > > > > // ----------------------------------------------------- Instance Variables > > > > > > /** > > * The descriptive information about this implementation. > > */ > > protected static final String info = > > "org.apache.catalina.logger.JdkLogger/1.0"; > > > > /** > > * The lifecycle event support for this component. > > */ > > protected LifecycleSupport lifecycle = new LifecycleSupport(this); > > > > /** > > * The string manager for this package. > > */ > > private StringManager sm = > > StringManager.getManager(Constants.Package); > > > > /** > > * Has this component been started? > > */ > > private boolean started = false; > > > > > > /** > > * The default JDK logging domain that these messages are logged to > > */ > > private String domain = "tomcat"; > > > > > > /** > > * The we are using. We set it immediately incase we get calls > > */ > > private Logger jlog = Logger.getLogger(domain); > > > > > > // ------------------------------------------------------------- Properties > > > > > > > > /** > > * Return the logging domain in which we create log files. > > */ > > public String getDomain() { > > > > return (domain); > > > > } > > > > > > /** > > * Set the domain in which we send our log files > > * > > * @param domain The new domain > > */ > > public void setDomain(String domain) { > > > > String oldDomain = this.domain; > > this.domain = domain; > > support.firePropertyChange("domain", oldDomain, this.domain); > > > > // there doesnt seem to be any semantics for changing a Logger's name, so > > // we just replace it. > > jlog = Logger.getLogger(domain); > > } > > > > > > // --------------------------------------------------------- Public Methods > > > > /** > > * Writes an explanatory message and a stack trace for a given > > * Throwable exception to the logger. > > * This message will be logged unconditionally. > > * > > * @param message A String that describes the error or > > * exception > > * @param exception The Exception error or exception > > */ > > public void log(Exception exception, String message){ > > logCallerStack( Level.INFO, message, exception ); > > } > > > > /** > > * Writes an explanatory message and a stack trace for a given > > * Throwable exception to the logger > > * This message will be logged unconditionally. > > * > > * @param message A String that describes the error or > > * exception > > * @param throwable The Throwable error or exception > > */ > > public void log(String message, Throwable throwable){ > > logCallerStack( Level.INFO, message, throwable ); > > } > > > > /** > > * Writes the specified message and exception to the logger, > > * if the logger is set to a verbosity level equal > > * to or higher than the specified value for this message. > > * > > * @param message A String the message to log > > * @param verbosity Verbosity level of this message > > */ > > public void log(String message, int verbosity){ > > if (this.verbosity < verbosity) > > return; > > > > // Translate tomcat verbosity into JDK Levels > > Level jlevel = Level.INFO; > > if ( verbosity == FATAL ) jlevel = Level.SEVERE; > > else if ( verbosity == ERROR ) jlevel = Level.SEVERE; > > else if ( verbosity == WARNING ) jlevel = Level.WARNING; > > else if ( verbosity == DEBUG ) jlevel = Level.FINE; > > > > logCallerStack( jlevel, message, null ); > > } > > > > /** > > * Writes the specified message and exception to the logger, > > * if the logger is set to a verbosity level equal > > * to or higher than the specified value for this message. > > * > > * @param message A String that describes the error or > > * exception > > * @param throwable The Throwable error or exception > > * @param verbosity Verbosity level of this message > > */ > > public void log(String message, Throwable throwable, int verbosity){ > > if (this.verbosity < verbosity) > > return; > > > > // Translate tomcat verbosity into JDK Levels > > Level jlevel = Level.INFO; > > if ( verbosity == FATAL ) jlevel = Level.SEVERE; > > else if ( verbosity == ERROR ) jlevel = Level.SEVERE; > > else if ( verbosity == WARNING ) jlevel = Level.WARNING; > > else if ( verbosity == DEBUG ) jlevel = Level.FINE; > > > > logCallerStack( jlevel, message, throwable ); > > } > > > > > > /** > > * Writes the specified message to a the logger > > * > > * @param message A String specifying the message to be logged > > */ > > public void log(String message) { > > logCallerStack( Level.INFO, message, null ); > > } > > > > > > // -------------------------------------------------------- Private Methods > > > > /** > > * Writes the specified message to a the logger and attempts to unroll > > * the stack to include the Class and method of the caller. Trys to be > > * clever by detecting other wrappers around logging (ie. frames with > > * methods name log() and internalLog() are skipped in determing the > > * messages stack of origin) > > * > > * @param jLevel A java.util.logging.Level instance to indicate the desired logging level > > * @param message A String specifying the message to be logged > > * @param throwable The Throwable error or exception > > */ > > private void logCallerStack( Level jlevel, String message, Throwable throwable ){ > > // Hack (?) to get the stack trace. > > Throwable dummyException=new Throwable(); > > StackTraceElement locations[]=dummyException.getStackTrace(); > > // Caller will be the third element > > String cname="unknown"; > > String method="unknown"; > > > > // tomcat has methods named log() and internalLog() that are sometimes on the stack > > if( locations!=null && locations.length >2 ) { > > StackTraceElement caller=null; > > for (int stackLevel=2;stackLevel > caller = locations[stackLevel]; > > method=caller.getMethodName(); > > if ( !method.equals("log") && !method.equals("internalLog") ){ > > cname=caller.getClassName(); > > // method += " [DEPTH "+stackLevel+"]"; uncomment this to see how much stack walking is going on. > > break; > > } > > } > > } > > if( throwable==null ) { > > jlog.logp( jlevel, cname, method, message ); > > } else { > > jlog.logp( jlevel, cname, method, message, throwable ); > > } > > > > } > > > > > > // ------------------------------------------------------ Lifecycle Methods > > > > > > /** > > * Add a lifecycle event listener to this component. > > * > > * @param listener The listener to add > > */ > > public void addLifecycleListener(LifecycleListener listener) { > > > > lifecycle.addLifecycleListener(listener); > > > > } > > > > > > /** > > * Get the lifecycle listeners associated with this lifecycle. If this > > * Lifecycle has no listeners registered, a zero-length array is returned. > > */ > > public LifecycleListener[] findLifecycleListeners() { > > > > return lifecycle.findLifecycleListeners(); > > > > } > > > > > > /** > > * Remove a lifecycle event listener from this component. > > * > > * @param listener The listener to add > > */ > > public void removeLifecycleListener(LifecycleListener listener) { > > > > lifecycle.removeLifecycleListener(listener); > > > > } > > > > > > /** > > * Prepare for the beginning of active use of the public methods of this > > * component. This method should be called after configure(), > > * and before any of the public methods of the component are utilized. > > * > > * @exception LifecycleException if this component detects a fatal error > > * that prevents this component from being used > > */ > > public void start() throws LifecycleException { > > > > // Validate and update our current component state > > if (started) > > throw new LifecycleException( "alreadyStarted"); > > lifecycle.fireLifecycleEvent(START_EVENT, null); > > started = true; > > > > } > > > > > > /** > > * Gracefully terminate the active use of the public methods of this > > * component. This method should be the last one called on a given > > * instance of this component. > > * > > * @exception LifecycleException if this component detects a fatal error > > * that needs to be reported > > */ > > public void stop() throws LifecycleException { > > > > // Validate and update our current component state > > if (!started) > > throw new LifecycleException("notStarted"); > > lifecycle.fireLifecycleEvent(STOP_EVENT, null); > > started = false; > > > > } > > > > > > } > > > > > > > > > > > > ------------------------------------------------------------------------ > > > > -- > > To unsubscribe, e-mail: > > For additional commands, e-mail: > > > -- > ________________________________________________________________ > Patrick Luby Email: patrick.luby@sun.com > Sun Microsystems Phone: 408-276-7471 > 901 San Antonio Road, USCA14-303 > Palo Alto, CA 94303-4900 > ________________________________________________________________ > > > -- > To unsubscribe, e-mail: > For additional commands, e-mail: -- To unsubscribe, e-mail: For additional commands, e-mail: