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 [EMAIL PROTECTED] * * 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/>. * * [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 <b>Logger</b> 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 * <code>Throwable</code> exception to the logger. * This message will be logged unconditionally. * * @param message A <code>String</code> that describes the error or * exception * @param exception The <code>Exception</code> 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 * <code>Throwable</code> exception to the logger * This message will be logged unconditionally. * * @param message A <code>String</code> that describes the error or * exception * @param throwable The <code>Throwable</code> 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 <code>String</code> 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 <code>String</code> that describes the error or * exception * @param throwable The <code>Throwable</code> 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 <code>String</code> 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 <code>java.util.logging.Level</code> instance to indicate the desired logging level * @param message A <code>String</code> specifying the message to be logged * @param throwable The <code>Throwable</code> 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<locations.length;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 <code>configure()</code>, * 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: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>