Frage

Ich habe eine Java-Anwendung, die log4j verwendet.

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 alle Log-Anweisungen korrekt an die Datei angehängt, aber ich bin zu verlieren stdout und stderr. Wie kann ich Ausnahme Stack-Traces und sysouts auf die tägliche gewalzte Datei umleiten?

War es hilfreich?

Lösung

// 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);
            }
        };
    }
}

Andere Tipps

In Skaffman Code: Um Leerzeilen in log4j Protokolle zu entfernen, fügen Sie einfach "println" Methode Print von 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);
        }
    };
}

ich die Idee von Michael S. aufgenommen, aber wie in einem Kommentar erwähnt, es hat einige Probleme. Es nicht alles erfassen, und er druckt einige leere Zeilen

Auch wollte ich System.out und System.err trennen, so dass System.out wird mit Protokollebene 'INFO' und System.err wird mit 'ERROR' angemeldet angemeldet (oder 'WARN' wenn Sie mögen).

Das ist also meine Lösung: Zunächst wird eine Klasse, die OutputStream (es ist einfacher, außer Kraft zu setzen alle Methoden für OutputStream als für PrintStream) erstreckt. Es meldet sich mit einem bestimmten Protokollebene und auch kopiert alles auf einen anderen OutputStream. Und auch erkennt es „leer“ Strings (mit Leerzeichen nur) und loggt sie nicht.

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);
}
}

Und dann eine sehr einfache Utility-Klasse zu setzen out und 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)));
}

}

Wenn Sie einen Anwendungsserver, Servlet-Container oder etwas ähnliches verwenden, finden Sie kgiannakakis Antwort .

Für Standalone-Anwendungen finden Sie unter dieser . Sie können reassing stdin , stdout und stderr mit java.lang.System Klasse. Grundsätzlich Sie eine neue Unterklasse von Print erstellen und diese Instanz zu System.out gesetzt.

Etwas in diese Richtung in Start der App (nicht getestet).

// 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());

Die Antworten über eine ausgezeichnete Idee geben Proxy für den STDOUT / ERR-Protokollierung zu verwenden. Vorausgesetzt jedoch Implementierungsbeispiele für alle Fälle nicht gut funktionieren. Zum Beispiel versucht

  

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

Der Code aus obigen Beispielen wird die Ausgabe in getrennte Stücke auf einer Konsole geschnitten und in mehreren nicht lesbar Log4j Einträge.

Die Lösung ist, die Ausgabe, bis ein Trigger zu puffern ‚\ n‘ am Ende des Puffers gefunden wird. Manchmal endet der Puffer mit ‚\ r \ n‘. Die Klasse unter behebt dieses Problem. Es ist voll funktionsfähig. Rufen Sie die statische Methode bind () zu aktivieren.

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  

}

Ich nehme an, Sie sind Anmeldung stacktraces über e.printStackTrace()? Sie können eine Ausnahmeobjekt in die Log4j Logging-Methoden übergeben und diese werden in dem Protokoll (siehe Logger.error (Object obj, Throwable t) )

Beachten Sie, dass Sie System.out und System.err zum anderen Print , die Log4j umleitet. Das würde eine einfache Änderung und speichern Sie alle Ihre System.out.println() Aussagen zu konvertieren.

Standardausgabe und Fehlerströme werden von Ihrem Container verwalten. Zum Beispiel Tomcat verwendet JULI Strom ausgegeben und Fehler zu protokollieren.

Meine Empfehlung ist, diese zu verlassen, wie es ist. Vermeiden Sie System.out.print in Ihrer Anwendung verwenden. Siehe hier Stack-Traces.

Die Anser von @ Michael ist ein guter Punkt. Aber Print erstreckt, ist nicht sehr schön, weil es eine interne Methode void write(String) nutzt alle Dinge zu einem Output schreiben zu können.

Ich ziehe den LoggingOutputStream Klasse aus dem Log4J Contrib-Paket.

Dann leite ich die Systemströme wie folgt aus:

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);
    }
}

Vor der System.setOut und System.setErr Methode sollten wir das java.util.logging.LogManager Objekt zurück, indem Sie Reset () Methode verwendet wird.

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();
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top