package edu.stanford.nlp.util.logging;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import edu.stanford.nlp.util.Generics;
/**
* A class to redirect the output of Redwood to another logging mechanism,
* e.g., java.util.logging.
*
* @author Gabor Angeli
*/
public class RedirectOutputHandler<LoggerClass, ChannelEquivalent> extends OutputHandler {
public final LoggerClass logger;
public final Method loggingMethod;
private final Map<Object, ChannelEquivalent> channelMapping;
private final ChannelEquivalent defaultChannel;
/**
* Create a redirect handler, with a logging class, ignoring logging
* levels.
* @param logger The class to use for logging. For example, java.util.logging.Logger
* @param loggingMethod A method which takes a *single* String argument
* and logs that string using the |logger| class.
*/
public RedirectOutputHandler(LoggerClass logger, Method loggingMethod) {
this(logger, loggingMethod, null, null);
}
/**
* Create a redirect handler, with a logging class, redirecting both the logging
* message, and the channel that it came from
* @param logger The class to use for logging. For example,
* java.util.logging.Logger
* @param loggingMethod A method which takes a *single* String argument
* and logs that string using the |logger| class.
* @param channelMapping The mapping from Redwood channels, to the native Channel equivalent.
*/
public RedirectOutputHandler(LoggerClass logger, Method loggingMethod,
Map<Object, ChannelEquivalent> channelMapping,
ChannelEquivalent defaultChannel) {
this.logger = logger;
this.loggingMethod = loggingMethod;
this.channelMapping = channelMapping;
this.defaultChannel = defaultChannel;
}
private boolean shouldLogChannels() {
return channelMapping != null;
}
@Override
public void print(Object[] channels, String line) {
if (line.endsWith("\n")) {
line = line.substring(0, line.length() - 1);
}
if (shouldLogChannels()) {
// -- Case: log with channel
// (get channel to publish on)
ChannelEquivalent channel = null;
if (channels == null) {
// (case: no channel provided)
channel = defaultChannel;
} else {
for (Object candidate : channels) {
if (channel == null) {
// (case: channel found in mapping)
channel = channelMapping.get(candidate);
}
}
if (channel == null) {
// (case: no channel found in mapping)
channel = this.defaultChannel;
}
}
// (publish message)
try {
this.loggingMethod.invoke(this.logger, channel, line);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (InvocationTargetException e) {
throw new IllegalStateException(e.getCause());
}
} else {
// -- Case: log without channel
try {
this.loggingMethod.invoke(this.logger, line);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (InvocationTargetException e) {
throw new IllegalStateException(e.getCause());
}
}
}
/**
* Ensure that we don't print duplicate channels when adapting to another logging framework.
* @inheritDoc
*/
@Override
protected boolean formatChannel(StringBuilder b, String channelStr, Object channel){
return !(channelMapping != null && channelMapping.containsKey(channel));
}
//
// LOGGER IMPLEMENTATIONS
//
public static RedirectOutputHandler<java.util.logging.Logger, java.util.logging.Level> fromJavaUtilLogging(java.util.logging.Logger logger) {
Map <Object, java.util.logging.Level> channelMapping = Generics.newHashMap();
channelMapping.put(Redwood.WARN, java.util.logging.Level.WARNING);
channelMapping.put(Redwood.DBG, java.util.logging.Level.FINE);
channelMapping.put(Redwood.ERR, java.util.logging.Level.SEVERE);
try {
return new RedirectOutputHandler<>(
logger,
java.util.logging.Logger.class.getMethod("log", java.util.logging.Level.class, String.class),
channelMapping,
java.util.logging.Level.INFO
);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(e);
}
}
}