Log4j redirect stdout to DailyRollingFileAppender

I have a java application that uses log4j.

Config:

log4j.rootLogger=info, file log4j.appender.file=org.apache.log4j.DailyRollingFileAppender log4j.appender.file.File=${user.home}/logs/app.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d [%t] %c %p %m%n 

So, all the log statements are correctly added to the file, but I am losing stdout and stderr. How to redirect traces of the exception stack and sysouts to a daily minimized file?

+55
java redirect file stdout log4j
Jul 29 '09 at 13:15
source share
9 answers
 // I set up a ConsoleAppender in Log4J to format Stdout/Stderr log4j.rootLogger=DEBUG, CONSOLE log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=[%t] %-5p %c - %m%n // And I call this StdOutErrLog.tieSystemOutAndErrToLog() on startup public 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); } }; } } 
+87
Sep 02 '09 at 20:51
source share

In Skaffman code: To remove blank lines in log4j logs, just add the "println" method to PrintStream 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); } }; } 
+10
Sep 11
source share

I chose the idea of ​​Michael S., but, as mentioned in one comment, she has some problems: she does not capture everything and prints several blank lines.

I also wanted to highlight System.out and System.err , so that System.out will be logged with the 'INFO' log level and System.err will be logged with 'ERROR' (or 'WARN' if you want).

So, this is my solution: First, a class that extends OutputStream (to simplify overriding all methods for OutputStream than for PrintStream ). It is logged with the specified log level, and also copies everything to another OutputStream . It also detects "empty" lines (containing only spaces) and does not register 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; } @Override public void write(byte[] b) throws IOException { outputStream.write(b); String string = new String(b); if (!string.trim().isEmpty()) logger.log(logLevel, string); } @Override public 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); } @Override public 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 install 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))); } } 
+7
Sep 20 '11 at 1:20
source share

If you are using an application server, servlet container, or something similar, see kgiannakakis answer .

For stand-alone applications see this . You can reassing stdin , stdout and stderr using the java.lang.System class . Basically you create a new subclass of PrintStream and set this instance to System.out.

Something in this direction at the beginning of your application (unverified).

 // PrintStream object that prints stuff to log4j logger public class Log4jStream extends PrintStream { public void write(byte buf[], int off, int len) { try { // write stuff to Log4J logger } catch (Exception e) { } } } // reassign standard output to go to log4j System.setOut(new Log4jStream()); 
+5
Jul 29 '09 at 13:35
source share

I assume you are registering stacktraces via e.printStackTrace() ? You can pass the exception object to Log4j logging methods and they will appear in your log (see Logger.error (Object obj, Throwable t) )

Note that you can change System.out and System.err to another PrintStream , which redirects to Log4j. This will be a simple change and will save you from converting all your System.out.println() statements.

+2
Jul 29 '09 at 13:22
source share

The answers above give a great idea of ​​using proxies for logging STDOUT / ERR. However, provided that the implementation examples do not work well for all cases. For example, try

System.out.printf ("Testing% s \ n", "ABC");

The code from the above examples will cut the output into separate fragments on the console and into several unreadable Log4j entries.

The solution is to buffer the output until the trigger "\ n" is found at the end of the buffer. Sometimes the buffer ends with "\ r \ n". The class below addresses this issue. It is fully functional. Call the static bind () method to activate it.

 import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import org.apache.log4j.Level; import org.apache.log4j.Logger; // Based on // http://stackoverflow.com/questions/1200175/log4j-redirect-stdout-to-dailyrollingfileappender public class Log4jStdOutErrProxy { public static void bind() { bind(Logger.getLogger("STDOUT"), Logger.getLogger("STDERR")); } @SuppressWarnings("resource") public static void bind(Logger loggerOut, Logger loggerErr) { System.setOut(new PrintStream(new LoggerStream(loggerOut, Level.INFO, System.out), true)); System.setErr(new PrintStream(new LoggerStream(loggerErr, Level.ERROR, System.err), true)); } private static class LoggerStream extends OutputStream { private final Logger logger; private final Level logLevel; private final OutputStream outputStream; private StringBuilder sbBuffer; public LoggerStream(Logger logger, Level logLevel, OutputStream outputStream) { this.logger = logger; this.logLevel = logLevel; this.outputStream = outputStream; sbBuffer = new StringBuilder(); } @Override public void write(byte[] b) throws IOException { doWrite(new String(b)); } @Override public void write(byte[] b, int off, int len) throws IOException { doWrite(new String(b, off, len)); } @Override public void write(int b) throws IOException { doWrite(String.valueOf((char)b)); } private void doWrite(String str) throws IOException { sbBuffer.append(str); if (sbBuffer.charAt(sbBuffer.length() - 1) == '\n') { // The output is ready sbBuffer.setLength(sbBuffer.length() - 1); // remove '\n' if (sbBuffer.charAt(sbBuffer.length() - 1) == '\r') { sbBuffer.setLength(sbBuffer.length() - 1); // remove '\r' } String buf = sbBuffer.toString(); sbBuffer.setLength(0); outputStream.write(buf.getBytes()); outputStream.write('\n'); logger.log(logLevel, buf); } } } // inner class LoggerStream } 
+2
Jan 14 '15 at 19:04
source share

Standard output and error streams are managed from your container. For example, Tomcat uses JULI to register output and stream streams.

My recommendation is to leave them as they are. Avoid using System.out.print in your application. See here for a stack trace.

+1
Jul 29 '09 at 13:26
source share

Anser @ Michael is a good point. But the PrintStream extension is not very nice because it uses the internal void write(String) method to write all things to an OutputStream.

I prefer to use the LoggingOutputStream class from the Log4J Contrib package.

Then I redirect the system threads as follows:

 public class SysStreamsLogger { private static Logger sysOutLogger = Logger.getLogger("SYSOUT"); private static Logger sysErrLogger = Logger.getLogger("SYSERR"); public static final PrintStream sysout = System.out; public static final PrintStream syserr = System.err; public static void bindSystemStreams() { // Enable autoflush System.setOut(new PrintStream(new LoggingOutputStream(sysOutLogger, LogLevel.INFO), true)); System.setErr(new PrintStream(new LoggingOutputStream(sysErrLogger, LogLevel.ERROR), true)); } public static void unbindSystemStreams() { System.setOut(sysout); System.setErr(syserr); } } 
+1
Jun 18 '12 at 10:43
source share

Before using the System.setOut and System.setErr methods, we must reset the java.util.logging.LogManager object using the reset () method.

 public static void tieSystemOutAndErrToLog() { try{ // initialize logging to go to rolling log file LogManager logManager = LogManager.getLogManager(); logManager.reset(); // and output on the original stdout System.out.println("Hello on old stdout"); System.setOut(createLoggingProxy(System.out)); System.setErr(createLoggingProxy(System.err)); //Following is to make sure whether system.out and system.err is redirecting to the stdlog.log file System.out.println("Hello world!"); try { throw new RuntimeException("Test"); } catch (Exception e) { e.printStackTrace(); } }catch(Exception e){ logger.error("Caught exception at StdOutErrLog ",e); e.printStackTrace(); } } 
0
May 7, '17 at 13:20
source share



All Articles