package org.dresdenocl.logging.appender;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.Priority;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ThrowableInformation;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;
import org.dresdenocl.logging.LoggingPlugin;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.lang.builder.ToStringBuilder;
/**
* This class is a custom log4j appender that sends log4j events to the Eclipse Error Log.
* By default, the {@link ILog} of the {@link LoggingPlugin} is used. Plugins may, however,
* set their own log by calling {@link #setLog(ILog)}. If the {@link LoggingPlugin} has not been
* activated (e.g. if Eclipse is not running), the <code>ErrorLogAppender</code> will issue
* internal warning messages using the log4j error handling mechanism.
*
* @author Manoel Marques, adapted by Matthias Braeuer
*/
public class ErrorLogAppender extends AppenderSkeleton {
// the plugin log of the associated Eclipse plugin
private ILog pluginLog;
// the name of the plugin (cached for performance)
private String pluginName;
/**
* Creates a new <code>ErrorLogAppender</code>
*/
public ErrorLogAppender() {
super();
// use the logging plugin's log by default
Plugin loggingPlugin = LoggingPlugin.getDefault();
if (loggingPlugin != null) {
pluginLog = LoggingPlugin.getDefault().getLog();
pluginName = LoggingPlugin.ID;
}
}
/**
* Sets the Eclipse log instance
*
* @param log plug-in log
*/
public void setLog(ILog pluginLog) {
// precondition check
if (pluginLog == null) {
throw new IllegalArgumentException("The parameter 'pluginLog' was null."); //$NON-NLS-1$
}
this.pluginLog = pluginLog;
// get the plugin name
pluginName = pluginLog.getBundle().getSymbolicName();
}
/**
* Logs a logging event. The log4j log level is translated to the Eclipse {@link IStatus} levels
* as follows:
*
* <ul>
* <li>{@link Level#FATAL} => {@link IStatus#CANCEL}
* <li>{@link Level#ERROR} => {@link IStatus#ERROR}
* <li>{@link Level#WARN} => {@link IStatus#WARNING}
* <li>{@link Level#INFO} => {@link IStatus#INFO}
* <li>default => {@link IStatus#OK}
*
* @param event the <code>LoggingEvent</code> instance
*/
@Override
public void append(LoggingEvent event) {
ThrowableInformation throwableInformation;
Throwable throwable;
int level, severity;
// check invariants
if (!canAppend()) {
return;
}
// get the log level from the event
level = event.getLevel().toInt();
// logging is turned off
if (level == Priority.OFF_INT) {
return;
}
// get a thrown exception from the logging event, if there is one
throwableInformation = event.getThrowableInformation();
throwable = (throwableInformation != null) ? throwableInformation.getThrowable() : null;
// set the severity according to the log level
switch (level) {
case Priority.FATAL_INT:
severity = IStatus.CANCEL;
break;
case Priority.ERROR_INT:
severity = IStatus.ERROR;
break;
case Priority.WARN_INT:
severity = IStatus.WARNING;
break;
case Priority.INFO_INT:
severity = IStatus.INFO;
break;
default:
severity = IStatus.OK;
}
// log to the associated Eclipse Error Log
pluginLog.log(new Status(severity,pluginName,level,layout.format(event),throwable));
}
/**
* This method determines if there is a sense in attempting to append. It checks whether a
*
* <p>
* It checks whether the appender has already been {@link #close() closed}and whether there is a
* {@link #setLayout(org.apache.log4j.Layout) layout} set for the appender. If these checks fail,
* <code>false</code> is returned. Subclasses may override to provide additional checks,
* </p>
*
* @return <code>true</code> if the conditions for appending a log event are met,
* <code>false</code> otherwise
*/
protected boolean canAppend() {
if (closed) {
LogLog.warn("Tried to write to closed appender [" + name + "]."); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
if (layout == null) {
errorHandler.error("Missing layout for appender [" + name + "].",null, //$NON-NLS-1$ //$NON-NLS-2$
ErrorCode.MISSING_LAYOUT);
return false;
}
if (pluginLog == null) {
errorHandler.error("No plugin log set for appender [" + name + "].",null, //$NON-NLS-1$ //$NON-NLS-2$
ErrorCode.GENERIC_FAILURE);
return false;
}
return true;
}
/**
* Closes this appender
*/
@Override
public void close() {
closed = true;
}
/**
* Checks if this appender requires layout
*
* @return true if layout is required.
*/
@Override
public boolean requiresLayout() {
return true;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.SHORT_PREFIX_STYLE).append("pluginName", //$NON-NLS-1$
pluginName).toString();
}
}