From ad40b8fdb4c4b61de598aa28cc56087e4d3075c8 Mon Sep 17 00:00:00 2001 From: "Craig R. McClanahan" Date: Tue, 4 Dec 2001 04:28:03 +0000 Subject: [PATCH] Migrate the "logging" package from jakarta-commons-sandbox. git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/logging/trunk@138814 13f79535-47bb-0310-9956-ffa450edef68 --- .cvsignore | 3 + PROPOSAL.html | 92 ++++++++ build.properties.sample | 2 + build.xml | 216 ++++++++++++++++++ src/java/org/apache/commons/logging/Log.java | 50 ++++ .../commons/logging/Log4JCategoryLog.java | 108 +++++++++ .../org/apache/commons/logging/LogSource.java | 175 ++++++++++++++ .../org/apache/commons/logging/NoOpLog.java | 35 +++ .../org/apache/commons/logging/SimpleLog.java | 206 +++++++++++++++++ .../org/apache/commons/logging/package.html | 123 ++++++++++ 10 files changed, 1010 insertions(+) create mode 100644 .cvsignore create mode 100644 PROPOSAL.html create mode 100644 build.properties.sample create mode 100644 build.xml create mode 100644 src/java/org/apache/commons/logging/Log.java create mode 100644 src/java/org/apache/commons/logging/Log4JCategoryLog.java create mode 100644 src/java/org/apache/commons/logging/LogSource.java create mode 100644 src/java/org/apache/commons/logging/NoOpLog.java create mode 100644 src/java/org/apache/commons/logging/SimpleLog.java create mode 100644 src/java/org/apache/commons/logging/package.html diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..b1e4b87 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,3 @@ +build.properties +dist +target diff --git a/PROPOSAL.html b/PROPOSAL.html new file mode 100644 index 0000000..e5081c6 --- /dev/null +++ b/PROPOSAL.html @@ -0,0 +1,92 @@ + + +Proposal for Logging Library Package + + + +
+

Proposal for Logging Package

+
+ +

(0) Rationale

+ +

There is a great need for debugging and logging information inside of +Commons components such as HTTPClient and dbcp. However, there are many +logging APIs out there and it is difficult to choose among them. +

+ +

The Logging package will be an ultra-thin bridge between different logging +libraries. Commons components may use the Logging JAR to remove +compile-time/runtime dependencies on any particular logging package, +and contributors may write Log implementations for the library of their choice. +

+ +

(1) Scope of the Package

+ +

The package shall create and maintain a package that provides extremely +basic logging functionality and bridges to other, more sophisticated logging +implementations. +

+ +

+The package should : +

+

+ +

+Non-goals: +

+

+ +

(1.5) Interaction With Other Packages

+ +

Logging relies on: +

+ + + +

(2) Required Jakarta-Commons Resources

+ + + + +

(4) Initial Committers

+ +

The initial committers on the Logging component shall be:

+ + + + + diff --git a/build.properties.sample b/build.properties.sample new file mode 100644 index 0000000..736b6c2 --- /dev/null +++ b/build.properties.sample @@ -0,0 +1,2 @@ +# log4j.jar - log4j classes (see http://jakarta.apache.org/log4j) +log4j.jar=/java/log4j/log4j.jar diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..4977c6a --- /dev/null +++ b/build.xml @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/java/org/apache/commons/logging/Log.java b/src/java/org/apache/commons/logging/Log.java new file mode 100644 index 0000000..c75535e --- /dev/null +++ b/src/java/org/apache/commons/logging/Log.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE file. + */ + +package org.apache.commons.logging; + +/** + * A simple logging interface abstracting logging APIs. In order to be + * instantiated successfully by {@link LogFactory}, classes that implement + * this interface must have a constructor that takes a single String + * parameter representing the "name" of this Log. + * + * @author Rod Waldhoff + * @version $Id: Log.java,v 1.6 2001/12/04 04:28:03 craigmcc Exp $ + */ +public interface Log { + public void debug(Object message); + public void debug(Object message, Throwable t); + public void info(Object message); + public void info(Object message, Throwable t); + public void warn(Object message); + public void warn(Object message, Throwable t); + public void error(Object message); + public void error(Object message, Throwable t); + public void fatal(Object message); + public void fatal(Object message, Throwable t); + public boolean isDebugEnabled(); + public boolean isInfoEnabled(); + public void setLevel(int level); + public int getLevel(); + + /** All logging level. */ + public static final int ALL = Integer.MIN_VALUE; + /** "Debug" level logging. */ + public static final int DEBUG = 10000; + /** "Info" level logging. */ + public static final int INFO = 20000; + /** "Warn" level logging. */ + public static final int WARN = 30000; + /** "Error" level logging. */ + public static final int ERROR = 40000; + /** "Fatal" level logging. */ + public static final int FATAL = 50000; + /** No logging level. */ + public static final int OFF = Integer.MAX_VALUE; +} diff --git a/src/java/org/apache/commons/logging/Log4JCategoryLog.java b/src/java/org/apache/commons/logging/Log4JCategoryLog.java new file mode 100644 index 0000000..ff40f69 --- /dev/null +++ b/src/java/org/apache/commons/logging/Log4JCategoryLog.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE file. + */ + +package org.apache.commons.logging; + +import org.apache.log4j.Category; +import org.apache.log4j.Priority; + +/** + *

Implementation of {@link Log} that maps directly to a Log4J + * Category. Initial configuration of the corresponding + * Category instances should be done in the usual manner, as outlined in + * the Log4J documentation.

+ * + * @author Rod Waldhoff + * @version $Id: Log4JCategoryLog.java,v 1.6 2001/12/04 04:28:03 craigmcc Exp $ + */ +public class Log4JCategoryLog implements Log { + Category _category = null; + + public Log4JCategoryLog(String name) { + _category = Category.getInstance(name); + } + + public final void debug(Object message) { + _category.debug(message); + } + + public final void debug(Object message, Throwable t) { + _category.debug(message,t); + } + + public final void info(Object message) { + _category.info(message); + } + + public final void info(Object message, Throwable t) { + _category.info(message,t); + } + + public final void warn(Object message) { + _category.warn(message); + } + public final void warn(Object message, Throwable t) { + _category.warn(message,t); + } + + public final void error(Object message) { + _category.error(message); + } + + public final void error(Object message, Throwable t) { + _category.error(message,t); + } + + public final void fatal(Object message) { + _category.fatal(message); + } + + public final void fatal(Object message, Throwable t) { + _category.fatal(message,t); + } + + public final boolean isDebugEnabled() { + return _category.isDebugEnabled(); + } + + public final boolean isInfoEnabled() { + return _category.isInfoEnabled(); + } + + public final boolean isEnabledFor(Priority p) { + return _category.isEnabledFor(p); + } + + public final void setLevel(int level) { + switch(level) { + case Log.DEBUG: + _category.setPriority(Priority.DEBUG); + break; + case Log.INFO: + _category.setPriority(Priority.INFO); + break; + case Log.WARN: + _category.setPriority(Priority.WARN); + break; + case Log.ERROR: + _category.setPriority(Priority.ERROR); + break; + case Log.FATAL: + _category.setPriority(Priority.FATAL); + break; + default: + _category.setPriority(Priority.toPriority(level)); + break; + } + } + + public final int getLevel() { + return _category.getPriority().toInt(); + } + +} diff --git a/src/java/org/apache/commons/logging/LogSource.java b/src/java/org/apache/commons/logging/LogSource.java new file mode 100644 index 0000000..e617d35 --- /dev/null +++ b/src/java/org/apache/commons/logging/LogSource.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE file. + */ + +package org.apache.commons.logging; + +import java.util.HashMap; +import java.lang.reflect.Constructor; +import java.util.Iterator; +import java.lang.reflect.InvocationTargetException; + +/** + *

Factory for creating {@link Log} instances. Applications should call + * the makeNewLogInstance() method to instantiate new instances + * of the configured {@link Log} implementation class.

+ * + * @author Rod Waldhoff + * @version $Id: LogSource.java,v 1.4 2001/12/04 04:28:03 craigmcc Exp $ + */ +public class LogSource { + static protected HashMap _logs = new HashMap(); + static protected boolean _log4jIsAvailable = false; + static { + try { + if(null != Class.forName("org.apache.log4j.Category")) { + _log4jIsAvailable = true; + } else { + _log4jIsAvailable = false; + } + } catch(ClassNotFoundException e) { + _log4jIsAvailable = false; + } catch(ExceptionInInitializerError e) { + _log4jIsAvailable = false; + } catch(LinkageError e) { + _log4jIsAvailable = false; + } + } + + static protected Constructor _logimplctor = null; + static { + try { + setLogImplementation(System.getProperty("org.apache.commons.logging.log","org.apache.commons.logging.NoOpLog")); + } catch(SecurityException e) { + _logimplctor = null; + } catch(LinkageError e) { + _logimplctor = null; + } catch(NoSuchMethodException e) { + _logimplctor = null; + } catch(ClassNotFoundException e) { + _logimplctor = null; + } + } + + private LogSource() { + } + + /** + * Set the log implementation/log implementation factory + * by the name of the class. The given class + * must implement {@link Log}, and provide a constructor that + * takes a single {@link String} argument (containing the name + * of the log). + */ + static public void setLogImplementation(String classname) throws + LinkageError, ExceptionInInitializerError, + NoSuchMethodException, SecurityException, + ClassNotFoundException { + Class logclass = Class.forName(classname); + Class[] argtypes = new Class[1]; + argtypes[0] = "".getClass(); + _logimplctor = logclass.getConstructor(argtypes); + } + + /** + * Set the log implementation/log implementation factory + * by class. The given class must implement {@link Log}, + * and provide a constructor that takes a single {@link String} + * argument (containing the name of the log). + */ + static public void setLogImplementation(Class logclass) throws + LinkageError, ExceptionInInitializerError, + NoSuchMethodException, SecurityException { + Class[] argtypes = new Class[1]; + argtypes[0] = "".getClass(); + _logimplctor = logclass.getConstructor(argtypes); + } + + static public Log getInstance(String name) { + Log log = (Log)(_logs.get(name)); + if(null == log) { + log = makeNewLogInstance(name); + _logs.put(name,log); + } + return log; + } + + static public Log getInstance(Class clazz) { + return getInstance(clazz.getName()); + } + + /** + * Create a new {@link Log} implementation, based + * on the given name + *

+ * The specific {@link Log} implementation returned + * is determined by the value of the + * org.apache.commons.logging.log property. + * The value of org.apache.commons.logging.log may be set to + * the fully specified name of a class that implements + * the {@link Log} interface. This class must also + * have a public constructor that takes a single + * {@link String} argument (containing the name + * of the {@link Log} to be constructed. + *

+ * When httpclient.log is not set, + * or when no corresponding class can be found, + * this method will return a {@link Log4JCategoryLog} + * if the log4j {@link org.apache.log4j.Category} class is + * available in the {@link LogSource}'s classpath, or + * a {@link NoOpLog} if it is not. + * + * @param name the log name (or category) + */ + static public Log makeNewLogInstance(String name) { + Log log = null; + try { + Object[] args = new Object[1]; + args[0] = name; + log = (Log)(_logimplctor.newInstance(args)); + } catch (InstantiationException e) { + log = null; + } catch (IllegalAccessException e) { + log = null; + } catch (IllegalArgumentException e) { + log = null; + } catch (InvocationTargetException e) { + log = null; + } catch (NullPointerException e) { + log = null; + } + if(null == log) { + if(_log4jIsAvailable) { + return new Log4JCategoryLog(name); + } else { + log = new NoOpLog(name); + } + } + return log; + } + + /** + * Sets the log level for all {@link Log}s known + * to me. + */ + static public void setLevel(int level) { + Iterator it = _logs.entrySet().iterator(); + while(it.hasNext()) { + Log log = (Log)(it.next()); + log.setLevel(level); + } + } + + /** + * Returns a {@link String} array containing the names of + * all logs known to me. + */ + static public String[] getLogNames() { + return (String[])(_logs.keySet().toArray(new String[_logs.size()])); + } + +} diff --git a/src/java/org/apache/commons/logging/NoOpLog.java b/src/java/org/apache/commons/logging/NoOpLog.java new file mode 100644 index 0000000..1abdc4b --- /dev/null +++ b/src/java/org/apache/commons/logging/NoOpLog.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE file. + */ + +package org.apache.commons.logging; + +/** + *

Default implementation of Log that throws away all messages. No + * configurable system properties are supported.

+ * + * @author Rod Waldhoff + * @version $Id: NoOpLog.java,v 1.6 2001/12/04 04:28:03 craigmcc Exp $ + */ +public final class NoOpLog implements Log { + public NoOpLog() { } + public NoOpLog(String name) { } + public void debug(Object message) { } + public void debug(Object message, Throwable t) { } + public void info(Object message) { } + public void info(Object message, Throwable t) { } + public void warn(Object message) { } + public void warn(Object message, Throwable t) { } + public void error(Object message) { } + public void error(Object message, Throwable t) { } + public void fatal(Object message) { } + public void fatal(Object message, Throwable t) { } + public final boolean isDebugEnabled() { return false; } + public final boolean isInfoEnabled() { return false; } + public final void setLevel(int level) { } + public final int getLevel() { return Log.OFF; } +} diff --git a/src/java/org/apache/commons/logging/SimpleLog.java b/src/java/org/apache/commons/logging/SimpleLog.java new file mode 100644 index 0000000..e1475b5 --- /dev/null +++ b/src/java/org/apache/commons/logging/SimpleLog.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE file. + */ + +package org.apache.commons.logging; + +import java.util.Properties; +import java.util.Enumeration; +import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.text.DateFormat; +import java.util.Date; + +/** + *

Simple implementation of Log that sends all enabled log messages, + * for all defined loggers, to System.out. The following system properties + * are supported to configure the behavior of this logger:

+ * + * + *

In addition to looking for system properties with the names specified + * above, this implementation also checks for a class loader resource named + * "simplelog.properties", and includes any matching definitions + * from this resource (if it exists).

+ * + * @author Rod Waldhoff + * @version $Id: SimpleLog.java,v 1.6 2001/12/04 04:28:03 craigmcc Exp $ + */ +public class SimpleLog implements Log { + static protected final String _prefix = + "org.apache.commons.logging.simplelog."; + static protected final Properties _simplelogProps = new Properties(); + static protected boolean _showlogname = false; + static protected boolean _showtime = false; + static protected DateFormat _df = null; + + static { + // add all system props that start with the specified prefix + Enumeration enum = System.getProperties().propertyNames(); + while(enum.hasMoreElements()) { + String name = (String)(enum.nextElement()); + if(null != name && name.startsWith(_prefix)) { + _simplelogProps.setProperty(name,System.getProperty(name)); + } + } + + // add props from the resource simplelog.properties + InputStream in = + ClassLoader.getSystemResourceAsStream("simplelog.properties"); + if(null != in) { + try { + _simplelogProps.load(in); + in.close(); + } catch(java.io.IOException e) { + // ignored + } + } + try { + } catch(Throwable t) { + // ignored + } + _showlogname = "true".equalsIgnoreCase(_simplelogProps.getProperty(_prefix + "showlogname","true")); + _showtime = "true".equalsIgnoreCase(_simplelogProps.getProperty(_prefix + "showdate","true")); + if(_showtime) { + _df = new SimpleDateFormat(_simplelogProps.getProperty(_prefix + "dateformat","yyyy/MM/dd HH:mm:ss:SSS zzz")); + } + } + + protected static final int DEBUG = 5; + protected static final int INFO = 4; + protected static final int WARN = 3; + protected static final int ERROR = 2; + protected static final int FATAL = 1; + protected int _logLevel = 2; + + protected String _name = null; + + public SimpleLog(String name) { + _name = name; + + String lvl = _simplelogProps.getProperty(_prefix + "log." + _name); + int i = String.valueOf(name).lastIndexOf("."); + while(null == lvl && i > -1) { + name = name.substring(0,i); + lvl = _simplelogProps.getProperty(_prefix + "log." + name); + i = String.valueOf(name).lastIndexOf("."); + } + if(null == lvl) { + lvl = _simplelogProps.getProperty(_prefix + "defaultlog"); + } + + if("debug".equalsIgnoreCase(lvl)) { + _logLevel = DEBUG; + } else if("info".equalsIgnoreCase(lvl)) { + _logLevel = INFO; + } else if("warn".equalsIgnoreCase(lvl)) { + _logLevel = WARN; + } else if("error".equalsIgnoreCase(lvl)) { + _logLevel = ERROR; + } else if("fatal".equalsIgnoreCase(lvl)) { + _logLevel = FATAL; + } + } + + protected void log(int type, Object message, Throwable t) { + if(_logLevel >= type) { + StringBuffer buf = new StringBuffer(); + if(_showtime) { + buf.append(_df.format(new Date())); + buf.append(" "); + } + switch(type) { + case DEBUG: buf.append("[DEBUG] "); break; + case INFO: buf.append("[INFO] "); break; + case WARN: buf.append("[WARN] "); break; + case ERROR: buf.append("[ERROR] "); break; + case FATAL: buf.append("[FATAL] "); break; + } + if(_showlogname) { + buf.append(String.valueOf(_name)).append(" - "); + } + buf.append(String.valueOf(message)); + if(t != null) { + buf.append(" <"); + buf.append(t.toString()); + buf.append(">"); + t.printStackTrace(); + } + System.out.println(buf.toString()); + } + } + + public final void debug(Object message) { + log(DEBUG,message,null); + } + + public final void debug(Object message, Throwable t) { + log(DEBUG,message,t); + } + + public final void info(Object message) { + log(INFO,message,null); + } + + public final void info(Object message, Throwable t) { + log(INFO,message,t); + } + + public final void warn(Object message) { + log(WARN,message,null); + } + public final void warn(Object message, Throwable t) { + log(WARN,message,t); + } + + public final void error(Object message) { + log(ERROR,message,null); + } + + public final void error(Object message, Throwable t) { + log(ERROR,message,t); + } + + public final void fatal(Object message) { + log(FATAL,message,null); + } + + public final void fatal(Object message, Throwable t) { + log(FATAL,message,t); + } + + public final boolean isDebugEnabled() { + return (_logLevel >= DEBUG); + } + + public final boolean isInfoEnabled() { + return (_logLevel >= INFO); + } + + public final void setLevel(int level) { + _logLevel = level; + } + + public final int getLevel() { + return _logLevel; + } + +} diff --git a/src/java/org/apache/commons/logging/package.html b/src/java/org/apache/commons/logging/package.html new file mode 100644 index 0000000..123daba --- /dev/null +++ b/src/java/org/apache/commons/logging/package.html @@ -0,0 +1,123 @@ + +

Simple wrapper API around multiple logging APIs.

+ +

Overview

+ +

This package provides an API for logging in server-based applications that +can be used around a variety of different logging implementations, including +prebuilt support for the following:

+ + +

Configuring the Logging Package APIs

+ +

The Logging Package APIs are configured based on the values of system +properties, which are normally set on the command line that started your +application. The following system properties are global to all +Log implementations: +

+ +

If you do not specify the class name of the Log implementation to use, the +following algorithm is applied:

+ + + +

Additionally, each individual Log implementation may +support its own configuration properties. These will be documented in the +class descriptions for the corresponding implementation class.

+ +

Finally, some Log implementations (such as the one for Log4J) +require an external configuration file for the entire logging environment. +This file should be prepared in a manner that is specific to the actual logging +technology being used.

+ +

Using the Logging Package APIs

+ +

Use of the Logging Package APIs, from the perspective of an application +component, consists of the following steps:

+
    +
  1. Acquire a reference to an instance of + org.apache.commons.logging.Log, by calling the + factory method + + LogSource.makeNewLogInstance(). Your application can contain + references to multiple loggers that are used for different + purposes. A typical scenario for a server application is to have each + major component of the server use its own Log instance.
  2. +
  3. Optionally, you can dynamically change the logging detail level by + calling Log.setLevel() with + an appropriate constant from the Log interface. Note that, + in most cases, the underlying logging system configuration will have + been preconfigured by the system administrator.
  4. +
  5. Cause messages to be logged (if the corresponding detail level is enabled) + by calling appropriate methods (debug(), info(), + warn(), error, and fatal()).
  6. +
+ +

For example, you might use the following technique to initialize and +use a Log instance in an application component:

+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogSource;
+
+public class MyComponent {
+
+  protected Log log = LogSource.makeNewInstance("mycomponent");
+
+  // Called once at startup time
+  public void start() {
+    ...
+    log.info("MyComponent started");
+    ...
+  }
+
+  // Called once at shutdown time
+  public void stop() {
+    ...
+    log.info("MyComponent stopped");
+    ...
+  }
+
+  // Called repeatedly to process a particular argument value
+  // which you want logged if debugging is enabled
+  public void process(String value) {
+    ...
+    // Do the string concatenation only if logging is enabled
+    if (log.isDebugEnabled())
+      log.debug("MyComponent processing " + value);
+    ...
+  }
+
+}
+
+ +