blob: cb4ee3b7f95f04b21d4d7dcb1d4b2202cfa6f230 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE.txt file distributed with this work for
// additional information regarding copyright ownership. The ASF licenses this
// file to you under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
package org.apache.oodt.commons.io;
import java.util.Date;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;
/** The log.
*
* This class represents the application- or applet-wide logging facility. If your
* application needs to log messages, here's your class.
*
* <p>To log a message, you call one of the <code>get</code> methods of this class to
* yield a {@link LogWriter} object. You can then call methods like {@link
* LogWriter#println(String)} to log a line of text. A typical invocation is
*
* <pre>Log.get().println("Buffer of length " + length + " allocated.");</pre>
*
* <p>This logs the given text using the default source string, and under the default
* category, and timestamped with the current time. You can reuse the
* <code>LogWriter</code>, but the timestamp, source, and category won't change. You
* should get a fresh <code>LogWriter</code>.
*
* <p><strong>Sources</strong> identify independent origins of log messages, such as
* independent threads in a program, or independent programs. Sources are just strings.
* If you don't specify a source, you get a default source. You can set the default
* source with {@link #setDefaultSource}. You <em>always</em> get a source with every
* message, even if it's a default source. If you don't otherwise set a default source
* string, the source is "app".
*
* <p><strong>Categories</strong> identify different classes or priorites of messages.
* Categories can be simple strings like "warning" or "debug", or they can be complex
* objects. You get to define your categories. Your group ought to agree on categories,
* though. If you don't specify a category, you get a default category. You can set the
* default category with {@link #setDefaultCategory}. If you don't call that method, the
* default category is the String object "message".
*
* <p><strong>Streams</strong> identify independent activities within a program, which
* often have transient lifespans. They're <em>not</em> separate output streams, but
* instead are separate, named entities representing separate activities (although a
* {@link LogListener} may put messages into separate output streams identified by each
* stream). Activity streams are identified by strings. To indicate the start and stop
* of streams, call {@link #startStream} and {@link #stopStream}. These send
* stream-started and stream-stopped events to the log listeners, who may choose to pay
* attention to them or ignore them. You can use streams to indicate to the log the start
* and the stop of activities such as an analyst examining the system, or a server
* handling a particular client.
*
* <p>All messages logged with this class go to one or more {@link LogListener} objects.
* A LogListener accepts logging events, such as a message being logged, and does
* something with it, such as writing the message to a file. Call {@link #addLogListener}
* to add a log listener. Logging of a message, starting a stream, and stopping a stream
* all get turned into {@link LogEvent}s and are multicasted to every registered listener.
*
* <p>The logging facility bootstraps itself with one or more log listeners specified by
* the system property <code>org.apache.oodt.commons.io.Log.loggers</code>. This property must be a
* space-separated list of complete class names. The logging facility will create an
* object of each class listed and add it as if you had called
* <code>addLogListener</code>. (You can specify system properties on the command line or
* in the applet tag.)
*
* @see LogListener
* @see LogWriter
* @author Kelly
*/
public class Log {
/** Currently registered LogListeners.
*/
private static Vector listeners;
static {
listeners = new Vector();
String loggers = System.getProperty("org.apache.oodt.commons.io.Log.loggers", "");
StringTokenizer tokenizer = new StringTokenizer(loggers);
while (tokenizer.hasMoreTokens()) {
String className = tokenizer.nextToken();
try {
Class clazz = Class.forName(className);
LogListener listener = (LogListener) clazz.newInstance();
addLogListener(listener);
} catch (Exception e) {
System.err.println("Can't create log listener object from class " + className + ": " + e);
System.exit(1);
}
}
}
/** Get a writer to log messages.
*
* The writer will log messages with the current time, default category, and
* default source. Messages will go into the general log.
*
* @return A writer with which you can log messages.
*/
public static LogWriter get() {
if (lastWriter != null && !lastWriter.isFlushed())
return lastWriter;
else
return get(new Date(), getDefaultSource(), getDefaultCategory());
}
/** Get a writer to log messages.
*
* The writer will log messages with the current time, specified category, and
* default source. Messages will go into the general log.
*
* @param category The messages' category.
* @return A writer with which you can log messages.
*/
public static LogWriter get(Object category) {
return get(new Date(), getDefaultSource(), category);
}
/** Get a writer to log messages.
*
* The writer will log messages with the specified time, specified category, and
* specified source.
*
* @param timestamp The time for messages logged with the returned writer.
* @param source The source of the log message.
* @param category The messages' category.
* @return A writer with which you can log messages.
*/
public static synchronized LogWriter get(Date timestamp, String source, Object category) {
lastWriter = new LogWriter(timestamp, source, category);
return lastWriter;
}
/** Start a new log stream.
*
* This method notifies the {@link LogListener}s that a new logging stream has
* started.
*
* @param stream The name of the stream.
* @param timestamp The time the stream started. To use the current time, pass a new {@link Date} object.
* @param source A string identifying who or what started the stream.
*/
public static void startStream(String stream, Date timestamp, String source) {
LogEvent event = null;
for (Enumeration e = listeners.elements(); e.hasMoreElements();) {
// Lazily create the event.
if (event == null)
event = new LogEvent(stream, timestamp, source);
((LogListener) e.nextElement()).streamStarted(event);
}
}
/** Stop a stream.
*
* This method notifies the {@link LogListener}s that a logging stream has stopped.
*
* @param stream The name of the stream that stopped.
*/
public static void stopStream(String stream) {
LogEvent event = null;
for (Enumeration e = listeners.elements(); e.hasMoreElements();) {
// Lazily create the event.
if (event == null)
event = new LogEvent(stream);
((LogListener) e.nextElement()).streamStopped(event);
}
}
/** Log a message.
*
* The {@link LogWriter}s call this when they've built up a complete message and
* want it multicasted to the {@link LogListener}s.
*
* @param timestamp The message's timestamp.
* @param source The source label of the message.
* @param category The message's category.
* @param message The message.
*/
static void logMessage(Date timestamp, String source, Object category, String message) {
LogEvent event = null;
for (Enumeration e = listeners.elements(); e.hasMoreElements();) {
// Lazily create the event.
if (event == null)
event = new LogEvent(timestamp, source, category, message);
((LogListener) e.nextElement()).messageLogged(event);
}
}
/** Set the default source.
*
* This sets the default source label used for logging.
*
* @param source The new default source label.
*/
public static void setDefaultSource(String source) {
if (source == null)
throw new IllegalArgumentException("Can't set a null default source");
defaultSource = source;
}
/** Get the default source.
*
* @return The default source label.
*/
public static String getDefaultSource() {
return defaultSource;
}
/** Set the default category.
*
* This sets the category object that's used by default for logging.
*
* @param category The new default category object.
*/
public static void setDefaultCategory(Object category) {
if (category == null)
throw new IllegalArgumentException("Can't set a null default category");
defaultCategory = category;
}
/** Get the default category.
*
* @return The default category object.
*/
public static Object getDefaultCategory() {
return defaultCategory;
}
/** Add a log listener.
*
* The listener will be notified whenever a message is logged, a stream started,
* or a stream stopped.
*
* @param listener The listener to add.
*/
public static void addLogListener(LogListener listener) {
if (listener == null)
throw new IllegalArgumentException("Can't add a null log listener");
listeners.addElement(listener);
}
/** Remove a log listener.
*
* The listener won't receive anymore events unless it's added back.
*
* @param listener The listener to remove.
*/
public static void removeLogListener(LogListener listener) {
if (listener == null)
throw new IllegalArgumentException("Can't remove a null log listener");
listeners.removeElement(listener);
}
/** The default source label.
*/
private static String defaultSource = "app";
/** The default category object.
*/
private static Object defaultCategory = "message";
/** Last log writer created so it can be reused. */
private static LogWriter lastWriter;
/** Don't allow instantiation.
*
* When we convert to Java 2, this should throw UnsupportedOperationException.
*/
private Log() {}
}