blob: 24e891aeb47e83a6d4b673a9914f82877975a8f3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
/*
* $RCSfile: Logger.java,v $
* $Revision: 1.8 $ $Date: 2006/05/17 20:13:45 $
*/
package org.eclipse.jem.util.logger.proxy;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;
import java.util.logging.Level;
/**
* This is a base, UI independent logger. It will
* construct a consistent msg. body, and call an enfironment specific ILogRenderer.
* By default, this logger will use a console based ILogRenderer,
* and a J2EE Plugin identification.
*
* <p>
* When running outside of Eclipse, the trace and logging level come from the system properties
* <ul>
* <li>"debug" (="true") - The default is <code>false</code>.
* <li>"logLevel" (="level" where "level" is a level string, e.g. SEVERE, WARNING, etc. from the <code>java.util.logging.Level</code> class).
* The default is "WARNING".
* </ul>
*
*
* @since 1.0.0
*/
public class Logger {
// This is used by ILogRenderer2 to define the default level.
static class LocalLevel extends Level {
/**
* Comment for <code>serialVersionUID</code>
*
* @since 1.1.0
*/
private static final long serialVersionUID = -6273357074767854883L;
public LocalLevel(String name, int level) {
super(name, level);
}
}
private boolean fTraceMode = false; // will we actually punch trace messaged or not
private String fPluginID;
private ILogRenderer fRenderer = null;
private ILogRenderer2 renderer2 = null;
public String fLineSeperator;
private Level level;
private Level defaultLevel = Level.SEVERE; // By default only severe or greater are logged.
private String logFileName;
private final static String DefaultLoggerPlugin = ILogRenderer.DefaultPluginID;
static private Hashtable Loggers = new Hashtable(); // Keep track of all the Loggers
final protected static String[] LogMark = { "*** ERROR *** ", //$NON-NLS-1$
"[Trace] ", //$NON-NLS-1$
"+++ Warning +++ ", //$NON-NLS-1$
"Info " }; //$NON-NLS-1$
final protected static String Filler = " "; // Use this to indent msg. body //$NON-NLS-1$
protected Logger() {
this(ILogRenderer.DefaultPluginID);
}
protected Logger(String pluginID) {
fPluginID = pluginID;
setRenderer(new JDKConsoleRenderer(this)); // Set up default to this. Someone can change it later.
}
/**
* Return the stacktrace as a print formatted string.
* @param e
* @return the stacktrace as a string.
*
* @since 1.0.0
*/
public String exceptionToString(Throwable e) {
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
return stringWriter.toString();
}
/**
* Get the system default logger. This is used for clients that don't know if they
* are running in Eclipse or outside of it. This way they have a common logger format
* which switch correctly.
* @return default logger.
*
* @since 1.0.0
*/
static public Logger getLogger() {
Logger defaultLogger = (Logger) Loggers.get(DefaultLoggerPlugin);
if (defaultLogger == null) {
defaultLogger = new Logger();
defaultLogger.init();
Loggers.put(DefaultLoggerPlugin, defaultLogger);
}
return defaultLogger;
}
/**
* Get the logger for a specific plugin.
* @param pluginId
* @return logger for a specific pluggin.
*
* @since 1.0.0
*/
static public Logger getLogger(String pluginId) {
if (pluginId == null)
return Logger.getLogger();
Logger Logger = (Logger) Loggers.get(pluginId);
if (Logger == null) {
Logger = new Logger(pluginId);
Logger.init();
Loggers.put(pluginId, Logger);
}
return Logger;
}
/**
* Used by subclass to get a logger if it exists, but not create one.
* @param pluginId
* @return logger.
*
* @since 1.0.0
*/
static protected Logger getLoggerIfExists(String pluginId) {
if (pluginId == null)
return Logger.getLogger();
else
return (Logger) Loggers.get(pluginId);
}
/**
* Get the plugin id for this logger.
* @return pluginid
*
* @since 1.0.0
*/
public String getPluginID() {
return fPluginID;
}
/**
* Get the trace mode for this logger
* @return <code>true</code> if tracing is going on.
*
* @since 1.0.0
*/
public boolean getTraceMode() {
return fTraceMode;
}
/*
* Indent the Msg. Body to make it easier to read the log
*/
private void indentMsg(String msg, StringBuffer logMsg) {
// Line seperator is different on different platform, unix = \n, windows \r\n and mac \r
String sep = fLineSeperator;
if (msg.indexOf("\r\n") != -1) //$NON-NLS-1$
sep = "\r\n"; //$NON-NLS-1$
else if (msg.indexOf("\n") != -1) //$NON-NLS-1$
sep = "\n"; //$NON-NLS-1$
else if (msg.indexOf("\r") != -1) //$NON-NLS-1$
sep = "\r"; //$NON-NLS-1$
StringTokenizer tokenizer = new StringTokenizer(msg, sep);
boolean first = true;
while (tokenizer.hasMoreTokens()) {
if (first) {
first = false;
logMsg.append(Filler + tokenizer.nextToken());
} else
logMsg.append(fLineSeperator + Filler + tokenizer.nextToken());
}
}
/*
* If Eclipse is started with the -XDebug or -debug turn traces on for this Logger
* Creation date: (8/23/2001 7:37:04 PM)
*/
private void init() {
if (System.getProperty("debug") != null) //$NON-NLS-1$
fTraceMode = true;
level = defaultLevel = Level.parse(System.getProperty("logLevel", Level.WARNING.getName())); //$NON-NLS-1$
try {
fLineSeperator = System.getProperty("line.separator"); // Diff on Win/Unix/Mac //$NON-NLS-1$
} catch (Throwable e) {
fLineSeperator = "\n"; //$NON-NLS-1$
}
}
/*
* Generic log.
* Creation date: (8/24/2001 1:55:34 PM)
* @return java.lang.String
* @param msg java.lang.String
* @param type int
*/
private String logAny(String msg, int type) {
StringBuffer logMsg = new StringBuffer();
logMsg.append(fLineSeperator);
logMsg.append(LogMark[type]);
return punchLog(logRest(msg, logMsg), type);
}
/**
* This is to be used by renderers that want to put a msg out
* in a generic format. This just returns the string that
* should be logged. It puts things like headers on it.
*
* @param msg
* @param aLevel
* @return The generic message for the string and level.
*
* @since 1.0.0
*/
public String getGenericMsg(String msg, Level aLevel) {
StringBuffer genMsg = new StringBuffer(msg.length()+16);
genMsg.append(fLineSeperator);
genMsg.append(getLevelHeader(aLevel));
genMsg.append(": "); //$NON-NLS-1$
genMsg.append(new Date());
indentMsg(msg, genMsg);
return genMsg.toString();
}
private static final Level[] LEVEL_SEARCH = new Level[] {
Level.SEVERE,
Level.WARNING,
Level.INFO,
ILogRenderer2.TRACE
};
private static final String[] LEVEL_MARK = new String[] {
"*** ERROR ***", //$NON-NLS-1$
"+++ Warning +++", //$NON-NLS-1$
"Info", //$NON-NLS-1$
"[Trace]" //$NON-NLS-1$
};
private String getLevelHeader(Level aLevel) {
for (int i=0; i<LEVEL_SEARCH.length; i++)
if (LEVEL_SEARCH[i] == aLevel)
return LEVEL_MARK[i];
return aLevel.getName(); // Not found, just use level string.
}
// The write's are here for history. Will implement using log(obj, Level) for all of the types.
/**
* deprecated use log(Level, Exception)
* @param aLevel
* @param ex
* @return
*
* @since 1.0.0
*
*/
public String write(Level aLevel, Exception ex) {
return log(aLevel, ex);
}
/**
* deprecated use log(Throwable)
* @param ex
* @return
*
* @since 1.0.0
*
*/
public String write(Throwable ex) {
return log(ex);
}
/**
* deprecated use log(Object, Level)
* @param aLevel
* @param logEntry
* @return
*
* @since 1.0.0
*/
public String write(Level aLevel, Object logEntry) {
return log(logEntry, aLevel);
}
/**
* deprecated use log(String, Level)
* @param aLevel
* @param string
* @return
*
* @since 1.0.0
*/
public String write(Level aLevel, String string) {
return log(string, aLevel);
}
/**
* deprecated use log(Throwable, Level)
* @param aLevel
* @param ex
* @return
*
* @since 1.0.0
*/
public String write(Level aLevel, Throwable ex) {
return log(ex, aLevel);
}
/**
* deprecated use log(Throwable, Level)
* @param aLevel
* @param ex
* @return
*
* @since 1.0.0
*/
public String log(Level aLevel, Exception ex) {
return log(ex, aLevel);
}
/**
* deprecated use log(Throwable, Level)
* @param aLevel
* @param ex
* @return
*
* @since 1.0.0
*/
public String log(Level aLevel, Throwable ex) {
return log(ex, aLevel);
}
/**
* Get the logging level
* @return logging level
*
* @since 1.0.0
*/
public Level getLevel() {
return level;
}
/**
* Check if the requested level is being logged. (e.g. if current level is SEVERE, then FINE will not be logged).
* @param requestlevel
* @return <code>true</code> if the level will be logged.
*
* @since 1.0.0
*/
public boolean isLoggingLevel(Level requestlevel) {
if (requestlevel == ILogRenderer2.TRACE && !getTraceMode())
return false; // We aren't tracing but requested trace.
return !(requestlevel.intValue() < getLevel().intValue() || getLevel() == Level.OFF);
}
/**
* Log an error string.
* @param msg
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String logError(String msg) {
return log(msg, Level.SEVERE);
}
/**
* Log an error throwable
* @param e
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String logError(Throwable e) {
return log(e, Level.SEVERE);
}
/**
* Log an info message.
* @param msg
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String logInfo(String msg) {
return log(msg, Level.INFO);
}
/**
* Log a throwable as a warning.
* @param e
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String logInfo(Throwable e) {
return log(e, Level.INFO);
}
/**
* Append the string to logMsg buffer passed in. Append the date and format the
* string with nice indentation.
*
* @param msg
* @param logMsg
* @return the string from the logMsg after logging the rest.
*
* @since 1.0.0
*/
protected String logRest(String msg, StringBuffer logMsg) {
logMsg.append(new Date());
indentMsg(msg, logMsg);
return logMsg.toString();
}
/**
* Log the msg as trace only.
* @param msg
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String logTrace(String msg) {
if (fTraceMode)
return log(msg, ILogRenderer2.TRACE);
else
return ILogRenderer.NOLOG_DESCRIPTION;
}
/**
* Log the throwable as trace only.
* @param e
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String logTrace(Throwable e) {
return log(e, ILogRenderer2.TRACE);
}
/**
* Log the message as warning.
* @param msg
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String logWarning(String msg) {
return log(msg, Level.WARNING);
}
/**
* Log the throwable as a warning.
* @param e
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String logWarning(Throwable e) {
return log(e, Level.WARNING);
}
/**
* Ask the Renderer to punch the msg. in the log.. one
* caller at the time
* Creation date: (8/24/2001 9:19:17 AM)
* @return java.lang.String
* @param msg java.lang.String
* @param type int
*/
protected synchronized String punchLog(String msg, int type) {
return fRenderer.log(msg, type);
}
/**
* Set the renderer to use.
* @param renderer
*
* @since 1.0.0
*/
public void setRenderer(ILogRenderer renderer) {
fRenderer = renderer;
renderer2 = (renderer instanceof ILogRenderer2) ? (ILogRenderer2) renderer : null;
renderer.setTraceMode(getTraceMode());
}
/**
* Set the trace mode.
* @param flag <code>true</code> to turn on tracing.
*
* @since 1.0.0
*/
public void setTraceMode(boolean flag) {
fTraceMode = flag;
if (fRenderer != null)
fRenderer.setTraceMode(flag);
}
/**
* Set the level cutoff for logging. Anything below this level will not log.
* Do not set level to <code>ILogRenderer2.TRACE</code>. It doesn't make sense.
*
* @param level (Use <code>ILogRenderer2.DEFAULT</code> to restore to default for this logger.
*
* @since 1.0.0
*/
public void setLevel(Level level) {
this.level = level != ILogRenderer2.DEFAULT ? level : defaultLevel;
}
/**
* Set the default level for this logger. It won't touch the current level.
*
* @param level
*
* @since 1.0.0
*/
public void setDefaultLevel(Level level) {
this.defaultLevel = level;
}
/**
* Get the log file name.
* @return Returns the logFileName.
*/
public String getLogFileName() {
return logFileName;
}
/**
* Set the log file name.
* @param logFileName The logFileName to set.
*/
public void setLogFileName(String logFileName) {
this.logFileName = logFileName;
}
// Now all of the log() types that use a Level.
/**
* Log the throwable at the default level for a throwable.
* @param e
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(Throwable e) {
return log(e, ILogRenderer2.DEFAULT);
}
/**
* Log the throwable at the given level.
* @param e
* @param logLevel
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(Throwable e, Level logLevel) {
if (renderer2 != null) {
return renderer2.log(e, logLevel);
} else {
// Do it the old way.
String stackTrace = exceptionToString(e);
return logAny(stackTrace, getOldType(logLevel != ILogRenderer2.DEFAULT ? level : Level.SEVERE));
}
}
public String log(Object o) {
return log(o, ILogRenderer2.DEFAULT);
}
/**
* Log the object at the given level.
* @param o
* @param logLevel
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(Object o, Level logLevel) {
if (renderer2 != null) {
return renderer2.log(o, logLevel);
} else {
// Do it the old way.
return logAny(String.valueOf(o), getOldType(logLevel != ILogRenderer2.DEFAULT ? level : Level.FINEST));
}
}
// The following are added to match up with Hyades so that primitives can be logged too.
/**
* Log a boolean at the default level.
* @param b
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(boolean b) {
return log(b, ILogRenderer2.DEFAULT);
}
/**
* Log a boolean at the given level.
* @param b
* @param logLevel
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(boolean b, Level logLevel) {
if (renderer2 != null) {
return renderer2.log(b, logLevel);
} else {
// Do it the old way.
return logAny(String.valueOf(b), getOldType(logLevel != ILogRenderer2.DEFAULT ? level : Level.FINEST));
}
}
/**
* Log the character at the default level.
* @param c
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(char c) {
return log(c, ILogRenderer2.DEFAULT);
}
/**
* Log the character at the given level.
* @param c
* @param logLevel
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(char c, Level logLevel) {
if (renderer2 != null) {
return renderer2.log(c, logLevel);
} else {
// Do it the old way.
return logAny(String.valueOf(c), getOldType(logLevel != ILogRenderer2.DEFAULT ? level : Level.FINEST));
}
}
/**
* Log the byte at the default level.
* @param b
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(byte b) {
return log(b, ILogRenderer2.DEFAULT);
}
/**
* Log the byte at the given level.
* @param b
* @param logLevel
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(byte b, Level logLevel) {
if (renderer2 != null) {
return renderer2.log(b, logLevel);
} else {
// Do it the old way.
return logAny(String.valueOf(b), getOldType(logLevel != ILogRenderer2.DEFAULT ? level : Level.FINEST));
}
}
/**
* Log the short at the default level.
* @param s
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(short s) {
return log(s, ILogRenderer2.DEFAULT);
}
/**
* Log the short at the given level.
* @param s
* @param logLevel
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(short s, Level logLevel) {
if (renderer2 != null) {
return renderer2.log(s, logLevel);
} else {
// Do it the old way.
return logAny(String.valueOf(s), getOldType(logLevel != ILogRenderer2.DEFAULT ? level : Level.FINEST));
}
}
/**
* Log the int at the default level.
* @param i
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(int i) {
return log(i, ILogRenderer2.DEFAULT);
}
/**
* Log the int at the default level.
* @param i
* @param logLevel
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(int i, Level logLevel) {
if (renderer2 != null) {
return renderer2.log(i, logLevel);
} else {
// Do it the old way.
return logAny(String.valueOf(i), getOldType(logLevel != ILogRenderer2.DEFAULT ? level : Level.FINEST));
}
}
/**
* Log the long at the default level.
* @param l
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(long l) {
return log(l, ILogRenderer2.DEFAULT);
}
/**
* Log the long at the given level.
* @param l
* @param logLevel
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(long l, Level logLevel) {
if (renderer2 != null) {
return renderer2.log(l, logLevel);
} else {
// Do it the old way.
return logAny(String.valueOf(l), getOldType(logLevel != ILogRenderer2.DEFAULT ? level : Level.FINEST));
}
}
/**
* Log the float at the default level.
* @param f
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(float f) {
return log(f, ILogRenderer2.DEFAULT);
}
/**
* Log the float at the given level.
* @param f
* @param logLevel
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(float f, Level logLevel) {
if (renderer2 != null) {
return renderer2.log(f, logLevel);
} else {
// Do it the old way.
return logAny(String.valueOf(f), getOldType(logLevel != ILogRenderer2.DEFAULT ? level : Level.FINEST));
}
}
/**
* Log the double at the default level
* @param d
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(double d) {
return log(d, ILogRenderer2.DEFAULT);
}
/**
* Log the double at the given level
*
* @param d
* @param logLevel
* @return how it was logged. See <code>CONSOLE_DESCRIPTION.</code>
*
* @since 1.0.0
*/
public String log(double d, Level logLevel) {
if (renderer2 != null) {
return renderer2.log(d, logLevel);
} else {
// Do it the old way.
return logAny(String.valueOf(d), getOldType(logLevel != ILogRenderer2.DEFAULT ? level : Level.FINEST));
}
}
/*
* Turn new type into old type. The defaultLevel is the
* level to use if the incoming level is marked as default.
*/
private int getOldType(Level aLevel) {
if (aLevel == Level.SEVERE)
return ILogRenderer.LOG_ERROR;
else if (aLevel == Level.WARNING)
return ILogRenderer.LOG_WARNING;
else if (aLevel == Level.INFO)
return ILogRenderer.LOG_INFO;
else if (aLevel == ILogRenderer2.TRACE)
return ILogRenderer.LOG_TRACE;
else
return ILogRenderer.LOG_INFO;
}
}