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...@locus.apache.org on 2000/09/29 16:33:39 UTC
cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/util/log DefaultLogger.java Log.java LogAware.java Logger.java QueueLogger.java
costin 00/09/29 07:33:38
Added: src/share/org/apache/tomcat/util/log DefaultLogger.java
Log.java LogAware.java Logger.java QueueLogger.java
Log:
Forgot to add the log :-)
Revision Changes Path
1.1 jakarta-tomcat/src/share/org/apache/tomcat/util/log/DefaultLogger.java
Index: DefaultLogger.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.Writer;
import java.io.IOException;
/**
* Trivial logger that sends all messages to the default sink. To
* change default sink, call Logger.setDefaultSink(Writer)
*
* @author Alex Chaffee (alex@jguru.com)
* @since Tomcat 3.1
**/
public class DefaultLogger extends Logger {
/**
* Prints log message to default sink
*
* @param message the message to log.
*/
protected void realLog(String message) {
try {
defaultSink.write(message);
defaultSink.write(NEWLINE);
flush();
}
catch (IOException e) {
bad(e, message, null);
}
}
/**
* Prints log message to default sink
*
* @param message the message to log.
* @param t the exception that was thrown.
*/
protected void realLog(String message, Throwable t) {
try {
defaultSink.write(message);
defaultSink.write(NEWLINE);
defaultSink.write(throwableToString(t));
defaultSink.write(NEWLINE);
flush();
}
catch (IOException e) {
bad(e, message, t);
}
}
private void bad(Throwable t1, String message, Throwable t2)
{
System.err.println("Default sink is unwritable! Reason:");
if (t1 != null) t1.printStackTrace();
if (message != null) System.err.println(message);
if (t2 != null) t2.printStackTrace();
}
/**
* Flush the log.
*/
public void flush() {
try {
defaultSink.flush();
}
catch (IOException e) {
}
}
}
1.1 jakarta-tomcat/src/share/org/apache/tomcat/util/log/Log.java
Index: Log.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.*;
/**
* Corresponds to a log chanel - 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
* 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>
*
* 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).
* <p>
* Usage: <pre>
* class Foo {
* Log log = new Log("tc_log", "Foo"); // or...
* Log log = new Log("tc_log", this); // fills in "Foo" for you
* ...
* log.log("Something happened");
* ...
* log.log("Starting something", Logger.DEBUG);
* ...
* catch (IOException e) {
* log.log("While doing something", e);
* }
* </pre>
*
* @author Alex Chaffee [alex@jguru.com]
**/
public class Log {
// name of the logger ( each logger has a unique name,
// used as a key internally )
private String logname;
// string displayed at the beginning of each log line,
// to identify the source
private String prefix;
// The real logger object ( that knows to write to
// files, optimizations, etc)
private Logger logger;
// Do we need that?
// private Log proxy;
// -------------------- Various constructors --------------------
public Log() {
}
/**
* 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);
}
/**
* @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;
}
// -------------------- 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);
}
/**
* Logs the Throwable with level ERROR (assumes an exception is
* trouble; if it's not, use log(msg, t, level))
**/
public void log(String msg, Throwable t)
{
log(msg, t, Logger.ERROR);
}
/**
* Logs the message with given level
**/
public void log(String msg, int level)
{
log(msg, null, level);
}
/**
* Logs the message and Throwable to its logger or, if logger
* not found, to the default logger, which writes to the
* default sink, which is usually System.err
**/
public void log(String msg, Throwable t, int level)
{
if (prefix != null) {
// tuneme
msg = prefix + ": " + msg;
}
// // activate proxy if present
// if (proxy != null)
// logger = proxy.getLogger();
// 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);
}
// -------------------- Extra configuration stuff --------------------
public Logger getLogger() {
// if (proxy != null)
// logger = proxy.getLogger();
return logger;
}
/**
* Set a logger explicitly. Also resets the logname property to
* match that of the given log.
*
* <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;
}
/**
* Set the prefix string to be prepended to each message
**/
public void setLogPrefix(String prefix) {
this.prefix = prefix;
}
// /**
// * Set a "proxy" Log -- whatever that one says its
// * Logger is, use it
// **/
// public void setProxy(Log helper) {
// this.proxy = helper;
// }
// ???
// public Log getLog() {
// return this;
// }
}
1.1 jakarta-tomcat/src/share/org/apache/tomcat/util/log/LogAware.java
Index: LogAware.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;
/** Interface used by components that use Log services, and
* allow a controller to set the log destination and
* childs to log to their log channel.
*
* The asymetry is intentional.
*/
public interface LogAware {
/** Set the real logging destination.
* Called by a parrent to control where the component
* logs.
*/
public void setLogger(Logger logger);
/**
* Returns the log channel used by this component.
*/
public Log getLog();
}
1.1 jakarta-tomcat/src/share/org/apache/tomcat/util/log/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.log;
import java.io.Writer;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.io.FileWriter;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.*;
import java.util.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
// import javax.servlet.ServletException; // for throwableToString()
// import org.apache.tomcat.core.TomcatException; // for throwableToString()
import org.apache.tomcat.util.FastDateFormat;
/**
* 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)
* @since Tomcat 3.1
*/
public abstract class Logger {
// ----- static content -----
/**
* Verbosity level codes.
*/
public static final int FATAL = Integer.MIN_VALUE;
public static final int ERROR = 1;
public static final int WARNING = 2;
public static final int INFORMATION = 3;
public static final int DEBUG = 4;
// -------------------- Internal fields --------------------
protected static Writer defaultSink = new OutputStreamWriter(System.err);
// registered loggers
protected static Hashtable loggers = new Hashtable(5);
// default logger
public static Logger defaultLogger = new DefaultLogger();
static {
defaultLogger.setVerbosityLevel(DEBUG);
}
// Usefull for subclasses
private static final String separator = System.getProperty("line.separator", "\n");
public static final char[] NEWLINE=separator.toCharArray();;
/**
* Prints the log message on a specified logger.
*
* @param name the name of the logger.
* @param message the message to log.
* @param verbosityLevel what type of message is this?
* (WARNING/DEBUG/INFO etc)
*/
/*
public static void log(String logName, String message,
int verbosityLevel)
{
Logger logger = getLogger(logName);
if (logger != null)
logger.log(message, verbosityLevel);
}
*/
/**
* Prints the log message on a specified logger at the "default"
* log leve: INFORMATION
*
* @param name the name of the logger.
* @param message the message to log.
*/
/*
public static void log(String logName, String message)
{
Logger logger = getLogger(logName);
if (logger != null)
logger.log(message);
}
*/
/**
* 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;
}
public static Logger getLogger(String name) {
return (Logger) loggers.get(name);
}
/**
* Get the logger that prints to the default sink
* (usu. System.err)
**/
public static Logger getDefaultLogger() {
return defaultLogger;
}
public static Enumeration getLoggerNames() {
return loggers.keys();
}
public static void putLogger(Logger logger) {
loggers.put(logger.getName(), logger);
}
public static void removeLogger(Logger logger) {
loggers.remove(logger.getName());
}
/**
* 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;
}
// ----- instance (non-static) content -----
protected boolean custom = true;
protected Writer sink = defaultSink;
String path;
protected String name;
private int level = WARNING;
/**
* 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));
/**
* Is this Log usable?
*/
public boolean isOpen() {
return this.sink != null;
}
/**
* Prints the log message at the "default" log level: INFORMATION
*
* @param message the message to log.
*/
public final void log(String message) {
log(message, Logger.INFORMATION);
}
/**
* Prints the log message.
*
* @param message the message to log.
* @param verbosityLevel what type of message is this?
* (WARNING/DEBUG/INFO etc)
*/
public final void log(String message, int verbosityLevel) {
log(message, null, level);
}
/**
* Prints log message and stack trace, with verbosityLevel ERROR.
* This makes the assumption that throwables are exceptions which
* are errors by nature; if you disagree, you can always call
* log(msg, t, Logger.INFORMATION) or whatever.
*
* @param message the message to log.
* @param t the exception that was thrown. */
public final void log(String message, Throwable t)
{
log(message, t, ERROR);
}
/**
* 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 message, Throwable t,
int verbosityLevel)
{
if (matchVerbosityLevel(verbosityLevel)) {
if (t == null) {
realLog(message);
}
else {
realLog(message, t);
}
}
}
public boolean matchVerbosityLevel(int verbosityLevel) {
return verbosityLevel <= getVerbosityLevel();
}
/**
* Subclasses implement these methods which are called by the
* log(..) methods internally.
*
* @param message the message to log.
*/
protected abstract void realLog(String message);
/**
* 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);
/**
* Flush the log.
*/
public abstract void flush();
/**
* Close the log.
*/
public synchronized void close() {
this.sink = null;
loggers.remove(getName());
}
/**
* Get name of this log channel.
*/
public String getName() {
return this.name;
}
/**
* Set name of this log channel.
*
* @param name Name of this logger.
*/
public void setName(String name) {
this.name = name;
// Once the name of this logger is set, we add it to the list
// of loggers...
putLogger(this);
}
/**
* 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;
}
public String toString() {
return "Logger(" + getName() + ", " + getPath() + ")";
}
/** 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
try {
File file = new File(path);
if (!file.exists())
new File(file.getParent()).mkdirs();
this.sink = new FileWriter(path);
} 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 = WARNING;
else if ("fatal".equalsIgnoreCase(level))
this.level = FATAL;
else if ("error".equalsIgnoreCase(level))
this.level = ERROR;
else if ("information".equalsIgnoreCase(level))
this.level = INFORMATION;
else if ("debug".equalsIgnoreCase(level))
this.level = 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;
}
/**
* 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;
}
// public void setCustomOutput( String value ) {
// if ("true".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value))
// custom = true;
// else if ("false".equalsIgnoreCase(value) || "no".equalsIgnoreCase(value))
// custom = false;
// }
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 == false)
return;
else if (timestampRaw) {
buf.append(Long.toString(msec));
return;
}
else {
Date d = new Date(msec);
timestampFormatter.format(d, buf, position);
return;
}
}
// ----- Logger.Helper static inner class -----
}
1.1 jakarta-tomcat/src/share/org/apache/tomcat/util/log/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.log;
import java.io.Writer;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.util.Date;
import org.apache.tomcat.util.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 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.
*/
final protected void realLog(String message) {
realLog( message, null );
}
/**
* 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();
}
public String toString() {
return "QueueLogger(" + getName() + ", " + getPath() + ")";
}
/**
* This is an entry that is created in response to every
* Logger.log(...) call.
*/
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;
}
public void print( StringBuffer outSB) {
if (date!=0) {
formatTimestamp( date, outSB );
outSB.append(" - ");
}
if (message != null)
outSB.append(message);
if (t != null) {
outSB.append(" - ");
outSB.append(throwableToString( t ));
}
}
}
}
/**
* 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 {
QueueLogger.LogEntry logEntry =
(QueueLogger.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();
}
};
}