log4j redirect stdout to DailyRollingFileAppender
// I set up a ConsoleAppender in Log4J to format Stdout/Stderrlog4j.rootLogger=DEBUG, CONSOLElog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppenderlog4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayoutlog4j.appender.CONSOLE.layout.ConversionPattern=[%t] %-5p %c - %m%n// And I call this StdOutErrLog.tieSystemOutAndErrToLog() on startuppublic class StdOutErrLog { private static final Logger logger = Logger.getLogger(StdOutErrLog.class); public static void tieSystemOutAndErrToLog() { System.setOut(createLoggingProxy(System.out)); System.setErr(createLoggingProxy(System.err)); } public static PrintStream createLoggingProxy(final PrintStream realPrintStream) { return new PrintStream(realPrintStream) { public void print(final String string) { realPrintStream.print(string); logger.info(string); } }; }}
I picked up the idea from Michael S., but like mentioned in one comment, it has some problems: it doesn't capture everything, and it prints some empty lines.
Also I wanted to separate System.out
and System.err
, so that System.out
gets logged with log level 'INFO'
and System.err
gets logged with 'ERROR'
(or 'WARN'
if you like).
So this is my solution:First a class that extends OutputStream
(it's easier to override all methods for OutputStream
than for PrintStream
). It logs with a specified log level and also copies everything to another OutputStream
. And also it detects "empty" strings (containing whitespace only) and does not log them.
import java.io.IOException;import java.io.OutputStream;import org.apache.log4j.Level;import org.apache.log4j.Logger;public class LoggerStream extends OutputStream{private final Logger logger;private final Level logLevel;private final OutputStream outputStream;public LoggerStream(Logger logger, Level logLevel, OutputStream outputStream){ super(); this.logger = logger; this.logLevel = logLevel; this.outputStream = outputStream;}@Overridepublic void write(byte[] b) throws IOException{ outputStream.write(b); String string = new String(b); if (!string.trim().isEmpty()) logger.log(logLevel, string);}@Overridepublic void write(byte[] b, int off, int len) throws IOException{ outputStream.write(b, off, len); String string = new String(b, off, len); if (!string.trim().isEmpty()) logger.log(logLevel, string);}@Overridepublic void write(int b) throws IOException{ outputStream.write(b); String string = String.valueOf((char) b); if (!string.trim().isEmpty()) logger.log(logLevel, string);}}
And then a very simple utility class to set out
and err
:
import java.io.PrintStream;import org.apache.log4j.Level;import org.apache.log4j.Logger;public class OutErrLogger{public static void setOutAndErrToLog(){ setOutToLog(); setErrToLog();}public static void setOutToLog(){ System.setOut(new PrintStream(new LoggerStream(Logger.getLogger("out"), Level.INFO, System.out)));}public static void setErrToLog(){ System.setErr(new PrintStream(new LoggerStream(Logger.getLogger("err"), Level.ERROR, System.err)));}}
In Skaffman code : To remove empty lines in log4j logs, just add "println" method to PrintStream of createLoggingProxy
public static PrintStream createLoggingProxy(final PrintStream realPrintStream) { return new PrintStream(realPrintStream) { public void print(final String string) { logger.warn(string); } public void println(final String string) { logger.warn(string); } };}