package com.revolsys.logging.log4j; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.log4j.FileAppender; import org.apache.log4j.Layout; import org.apache.log4j.Logger; import org.apache.log4j.Priority; import org.apache.log4j.spi.ErrorHandler; import org.apache.log4j.spi.LoggingEvent; public class ThreadLocalFileAppender extends FileAppender { public static ThreadLocalFileAppender getAppender() { return getAppender("ThreadLocalLog"); } public static ThreadLocalFileAppender getAppender(final String name) { final Logger rootLogger = Logger.getRootLogger(); final ThreadLocalFileAppender appender = (ThreadLocalFileAppender)rootLogger.getAppender(name); return appender; } private final Map<String, FileAppender> appenders = new HashMap<>(); private final ThreadLocal<FileAppender> localAppender = new ThreadLocal<>(); private final ThreadLocal<String> localFile = new ThreadLocal<>(); public ThreadLocalFileAppender() { super(); } public ThreadLocalFileAppender(final Layout layout, final String filename) throws IOException { setLayout(layout); setFile(filename); } public ThreadLocalFileAppender(final Layout layout, final String filename, final boolean append) throws IOException { setLayout(layout); setFile(filename); setAppend(append); } public ThreadLocalFileAppender(final Layout layout, final String filename, final boolean append, final boolean bufferedIO, final int bufferSize) throws IOException { super(layout, filename, append, bufferedIO, bufferSize); } @Override public void activateOptions() { } @Override public void append(final LoggingEvent event) { if (hasLocalAppender()) { final FileAppender appender = getLocalAppender(); appender.append(event); } } @Override public void close() { if (hasLocalAppender()) { getLocalAppender().close(); } else { super.close(); } } @Override public boolean getAppend() { if (hasLocalAppender()) { return getLocalAppender().getAppend(); } else { return super.getAppend(); } } @Override public boolean getBufferedIO() { if (hasLocalAppender()) { return getLocalAppender().getBufferedIO(); } else { return super.getBufferedIO(); } } @Override public int getBufferSize() { if (hasLocalAppender()) { return getLocalAppender().getBufferSize(); } else { return super.getBufferSize(); } } @Override public String getEncoding() { if (hasLocalAppender()) { return getLocalAppender().getEncoding(); } else { return super.getEncoding(); } } @Override public ErrorHandler getErrorHandler() { if (hasLocalAppender()) { return getLocalAppender().getErrorHandler(); } else { return super.getErrorHandler(); } } @Override public String getFile() { if (hasLocalAppender()) { return getLocalAppender().getFile(); } else { return super.getFile(); } } private synchronized FileAppender getFileAppender(final String file) { FileAppender appender = this.appenders.get(file); if (appender == null) { appender = new FileAppender(); appender.setAppend(super.getAppend()); appender.setBufferedIO(super.getBufferedIO()); appender.setBufferSize(super.getBufferSize()); appender.setEncoding(super.getEncoding()); appender.setErrorHandler(super.getErrorHandler()); appender.setFile(file); appender.setImmediateFlush(super.getImmediateFlush()); appender.setLayout(super.getLayout()); appender.setName(super.getName()); appender.setThreshold(super.getThreshold()); appender.activateOptions(); this.appenders.put(file, appender); } return appender; } @Override public boolean getImmediateFlush() { if (hasLocalAppender()) { return getLocalAppender().getImmediateFlush(); } else { return super.getImmediateFlush(); } } @Override public Layout getLayout() { if (hasLocalAppender()) { return getLocalAppender().getLayout(); } else { return super.getLayout(); } } private FileAppender getLocalAppender() { if (hasLocalAppender()) { return this.localAppender.get(); } else { return null; } } public String getLocalFile() { return this.localFile.get(); } @Override public Priority getThreshold() { if (hasLocalAppender()) { return getLocalAppender().getThreshold(); } else { return super.getThreshold(); } } private boolean hasLocalAppender() { return this.localAppender.get() != null; } private FileAppender newLocalAppender() { final String file = getLocalFile(); final FileAppender fileAppender = getFileAppender(file); this.localAppender.set(fileAppender); return fileAppender; } public void removeLocalFile() { final String localFileName = this.localFile.get(); if (localFileName != null) { this.localAppender.set(null); this.localFile.set(null); final FileAppender appender = this.appenders.get(localFileName); if (appender != null) { appender.close(); this.appenders.remove(localFileName); } } } @Override public boolean requiresLayout() { return true; } @Override public void setAppend(final boolean append) { if (hasLocalAppender()) { getLocalAppender().setAppend(append); } else { super.setAppend(append); } } @Override public void setBufferedIO(final boolean bufferedIO) { if (hasLocalAppender()) { getLocalAppender().setBufferedIO(bufferedIO); } else { super.setBufferedIO(bufferedIO); } } @Override public void setBufferSize(final int bufferSize) { if (hasLocalAppender()) { getLocalAppender().setBufferSize(bufferSize); } else { super.setBufferSize(bufferSize); } } @Override public void setEncoding(final String encoding) { if (hasLocalAppender()) { getLocalAppender().setEncoding(encoding); } else { super.setEncoding(encoding); } } @Override public void setErrorHandler(final ErrorHandler errorHandler) { if (hasLocalAppender()) { getLocalAppender().setErrorHandler(errorHandler); } else { super.setErrorHandler(errorHandler); } } @Override public void setFile(final String file) { if (hasLocalAppender()) { getLocalAppender().setFile(file); } else { super.setFile(file); } } @Override public void setImmediateFlush(final boolean immediateFlush) { if (hasLocalAppender()) { getLocalAppender().setImmediateFlush(immediateFlush); } else { super.setImmediateFlush(immediateFlush); } } @Override public void setLayout(final Layout layout) { if (hasLocalAppender()) { getLocalAppender().setLayout(layout); } else { super.setLayout(layout); } } public void setLocalFile(final String file) { this.localFile.set(file); if (file != null) { newLocalAppender(); } } @Override public void setThreshold(final Priority threshold) { if (hasLocalAppender()) { getLocalAppender().setThreshold(threshold); } else { super.setThreshold(threshold); } } }