/*****************************************************************************
* Copyright (c) 2006-2013, Cloudsmith Inc.
* The code, documentation and other materials contained herein have been
* licensed under the Eclipse Public License - v 1.0 by the copyright holder
* listed above, as the Initial Contributor under such license. The text of
* such license is available at www.eclipse.org.
*****************************************************************************/
package org.eclipse.buckminster.runtime;
import java.io.OutputStream;
import java.io.PrintStream;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.ILogListener;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.osgi.framework.Bundle;
/**
* This logger will disptach all messages to two destinations; the eclipse
* logger and the console. Depending on the settings, the message might be
* dispatched to none, one, or both destinations. The logger can also be made to
* dispatch console messages through the eclipse logger. It does that by adding
* an ILogListener to the platform that will dispatch all messages to standard
* out.
*
* @author Thomas Hallgren
*/
public class Logger {
private static class EclipseLogListener implements ILogListener {
@Override
public void logging(IStatus status, String plugin) {
int severity = status.getSeverity();
if (severity >= consoleThreshold) {
PrintStream out;
switch (severity) {
case IStatus.ERROR:
case IStatus.WARNING:
out = System.err;
break;
default:
out = System.out;
}
Logger.printStatus(status, out);
}
}
}
public static final int SILENT = IStatus.CANCEL; // We use this constant to
// avoid collisions
public static final int DEBUG = IStatus.OK;
public static final int ERROR = IStatus.ERROR;
public static final int INFO = IStatus.INFO;
public static final int WARNING = IStatus.WARNING;
// Magic used as the bundle specific code in log entries. Can be used
// for filtering (although not in the Eclipse log viewer since it
// doesn't support filtering on plugin specific code yet)
//
private static final int MAGIC = 293;
private static Logger defaultLogger;
private static int consoleThreshold = IBuckminsterPreferenceConstants.LOG_LEVEL_CONSOLE_DEFAULT;
private static int eclipseLoggerThreshold = IBuckminsterPreferenceConstants.LOG_LEVEL_ECLIPSE_LOGGER_DEFAULT;
private static ILogListener eclipseLogListener;;
private static PrintStream errStream;
private static PrintStream outStream;
static {
setOutStream(getLoggerStream(false));
setErrStream(getLoggerStream(true));
}
public static Logger getDefault() {
return defaultLogger;
}
public static PrintStream getErrStream() {
return errStream;
}
public static PrintStream getOutStream() {
return outStream;
}
public static void printStatus(IStatus status, PrintStream out) {
synchronized (out) {
printStatus(status, out, 0);
out.flush();
}
}
public static void setConsoleLevelThreshold(int threshold) {
consoleThreshold = threshold;
}
public static void setEclipseLoggerLevelThreshold(int threshold) {
eclipseLoggerThreshold = threshold;
}
public static synchronized void setEclipseLoggerToConsole(boolean flag) {
if (flag) {
if (eclipseLogListener == null) {
eclipseLogListener = new EclipseLogListener();
Platform.addLogListener(eclipseLogListener);
}
} else {
if (eclipseLogListener != null) {
Platform.removeLogListener(eclipseLogListener);
eclipseLogListener = null;
}
}
}
public static void setErrStream(PrintStream err) {
errStream = err;
}
public static void setOutStream(PrintStream out) {
outStream = out;
}
static void setDefaultLogger(Bundle bundle) {
defaultLogger = new Logger(bundle);
}
private static PrintStream getLoggerStream(boolean errorStream) {
// collect all implementors of a builder log receiver and hook them all
// up in a tee
//
PrintStream sysStream = errorStream ? System.err : System.out;
if (Buckminster.isHeadless())
return sysStream;
IExtensionRegistry ier = Platform.getExtensionRegistry();
IConfigurationElement[] elems = ier.getConfigurationElementsFor(BUILDER_LOG_RECEIVER_POINT);
int idx = elems.length;
if (idx == 0)
return sysStream;
try {
OutputStream[] streams = new OutputStream[idx + 1];
streams[idx] = sysStream;
while (--idx >= 0) {
ILogReceiver receiver = (ILogReceiver) elems[idx].createExecutableExtension("class"); //$NON-NLS-1$
streams[idx] = receiver.start("Buckminster log", "org.eclipse.ui.MessageConsole", true, errorStream); //$NON-NLS-1$ //$NON-NLS-2$
}
return new PrintStream(new MultiTeeOutputStream(streams), true);
} catch (Exception t) {
// Workbench is not present
return sysStream;
}
}
private static void printStatus(IStatus status, PrintStream out, int indent) {
boolean hasSeverityPrefix = false;
String msg = status.getMessage();
if (msg != null)
hasSeverityPrefix = msg.startsWith("ERROR") || msg.startsWith("WARN") || msg.startsWith("INFO"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
for (int idx = 0; idx < indent; ++idx)
out.print(' ');
if (!hasSeverityPrefix) {
switch (status.getSeverity()) {
case IStatus.CANCEL:
return;
case IStatus.ERROR:
out.print("ERROR: "); //$NON-NLS-1$
break;
case IStatus.INFO:
out.print("INFO: "); //$NON-NLS-1$
break;
case IStatus.WARNING:
out.print("WARN: "); //$NON-NLS-1$
}
}
out.println(msg);
Throwable t = status.getException();
if (t != null)
t.printStackTrace(out);
indent += 2;
for (IStatus child : status.getChildren())
printStatus(child, out, indent);
}
private final ILog log;
public static final String BUILDER_LOG_RECEIVER_POINT = Buckminster.PLUGIN_ID + ".logReceivers"; //$NON-NLS-1$
public Logger(Bundle bundle) {
if (bundle == null)
throw new IllegalArgumentException("The bundle for a logger cannot be null"); //$NON-NLS-1$
log = Platform.getLog(bundle);
}
public Logger(ILog log) {
this.log = log;
}
public Logger(String bundleId) {
this(Platform.getBundle(bundleId));
}
public void debug(String msg, Object... args) {
log(DEBUG, msg, args);
}
public void debug(Throwable t, String msg, Object... args) {
log(DEBUG, t, msg, args);
}
public void error(String msg, Object... args) {
log(ERROR, msg, args);
}
public void error(Throwable t, String msg, Object... args) {
log(ERROR, t, msg, args);
}
public void info(String msg, Object... args) {
log(INFO, msg, args);
}
public void info(Throwable t, String msg, Object... args) {
log(INFO, t, msg, args);
}
public boolean isDebugEnabled() {
return consoleThreshold <= DEBUG || eclipseLoggerThreshold <= DEBUG;
}
public boolean isErrorEnabled() {
return consoleThreshold <= ERROR || eclipseLoggerThreshold <= ERROR;
}
public boolean isInfoEnabled() {
return consoleThreshold <= INFO || eclipseLoggerThreshold <= INFO;
}
public boolean isWarningEnabled() {
return consoleThreshold <= WARNING || eclipseLoggerThreshold <= WARNING;
}
public void log(int level, String msg, Object... args) {
log(level, null, msg, args);
}
public void log(int level, Throwable t, String msg, Object... args) {
if (level >= consoleThreshold && (eclipseLogListener == null || level < eclipseLoggerThreshold)) {
PrintStream logStream = (level == WARNING || level == ERROR) ? errStream : outStream;
synchronized (logStream) {
if (args == null || args.length == 0)
logStream.print(msg);
else
logStream.format(msg, args);
logStream.println();
if (t != null && consoleThreshold == DEBUG)
t.printStackTrace(logStream);
logStream.flush();
}
}
if (level >= eclipseLoggerThreshold)
log.log(new Status(level, log.getBundle().getSymbolicName(), MAGIC, (args == null || args.length == 0) ? msg : String.format(msg, args),
t));
}
public void warning(String msg, Object... args) {
log(WARNING, msg, args);
}
public void warning(Throwable t, String msg, Object... args) {
log(WARNING, t, msg, args);
}
}