package edu.brown.logging;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Category;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LocationInfo;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.ThrowableInformation;
public class FastLoggingEvent extends LoggingEvent {
private static final Logger LOG = Logger.getLogger(FastLoggingEvent.class);
private static final long serialVersionUID = -5595734504055550617L;
protected static final Pattern PREPROCESSOR_PATTERN = Pattern.compile("^([\\w]+\\.java):([\\d]+) ");
private final LoggingEvent event;
private final int stackOffset;
private FastLocationInfo locationInfo;
private String cleanMessage = null;
public FastLoggingEvent(LoggingEvent event, int stackOffset) {
super(event.getFQNOfLoggerClass(),
event.getLogger(),
event.getLevel(),
event.getMessage(),
(event.getThrowableInformation() != null ? event.getThrowableInformation().getThrowable() : null));
this.event = event;
this.stackOffset = stackOffset;
}
public static int getStackOffset(LoggingEvent event) {
Throwable t = new Throwable();
String fqnOfCallingClass = event.getFQNOfLoggerClass();
if (fqnOfCallingClass == null) return 0;
// HACK
StackTraceElement stack[] = t.getStackTrace();
int offset = stack.length - 1;
for (; offset >= 0; offset--) {
if (stack[offset].getClassName().equals(fqnOfCallingClass)) break;
} // FOR
return (offset + 2);
}
@Override
public LocationInfo getLocationInformation() {
if (this.locationInfo == null) {
// HACK: Use preprocessor information
String msg = this.event.getMessage().toString();
Matcher m = PREPROCESSOR_PATTERN.matcher(msg);
if (LOG.isDebugEnabled()) LOG.debug("Checking whether we can use PREPROCESSOR info for location: " + msg);
if (m.find()) {
if (LOG.isDebugEnabled()) LOG.debug("Using preprocessor information get source location [" + m + "]");
String fileName = m.group(1);
int lineNumber = Integer.parseInt(m.group(2));
this.locationInfo = new FastLocationInfo(lineNumber, fileName, "", "");
this.cleanMessage = m.replaceFirst("");
} else {
if (LOG.isDebugEnabled()) LOG.debug("Using stack offset lookup to get source location");
StackTraceElement stack[] = Thread.currentThread().getStackTrace();
// System.err.println(String.format("Stack=%d / Offset=%d", stack.length, this.stackOffset));
if (this.stackOffset < stack.length) {
// for (int i = 0; i < stack.length; i++) {
// System.err.printf("[%02d] %s\n", i, stack[i]);
// }
this.locationInfo = new FastLocationInfo(stack[this.stackOffset].getLineNumber(),
stack[this.stackOffset].getFileName(),
stack[this.stackOffset].getClassName(),
stack[this.stackOffset].getMethodName());
}
}
}
return (this.locationInfo);
}
@Override
public String getFQNOfLoggerClass() {
return event.getFQNOfLoggerClass();
}
@Override
public Level getLevel() {
return event.getLevel();
}
@Override
public Category getLogger() {
return event.getLogger();
}
@Override
public String getLoggerName() {
return event.getLoggerName();
}
@Override
public Object getMDC(String key) {
return event.getMDC(key);
}
@Override
public void getMDCCopy() {
event.getMDCCopy();
}
@Override
public Object getMessage() {
return (this.cleanMessage != null ? this.cleanMessage : this.event.getMessage());
}
@Override
public String getRenderedMessage() {
return (this.cleanMessage != null ? this.cleanMessage : this.event.getRenderedMessage());
}
@Override
public String getNDC() {
return event.getNDC();
}
@SuppressWarnings("rawtypes")
@Override
public Map getProperties() {
return event.getProperties();
}
@SuppressWarnings("rawtypes")
@Override
public Set getPropertyKeySet() {
return event.getPropertyKeySet();
}
@Override
public String getThreadName() {
return event.getThreadName();
}
@Override
public ThrowableInformation getThrowableInformation() {
return event.getThrowableInformation();
}
@Override
public String[] getThrowableStrRep() {
return event.getThrowableStrRep();
}
}