log4j redirige stdout vers DailyRollingFileAppender

J’ai une application java qui utilise 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 

Donc, toutes les instructions du journal sont correctement ajoutées au fichier, mais je perds stdout et stderr. Comment redirect les traces de stack d’exceptions et les sysouts vers le fichier journalier?

 // 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 Ssortingng ssortingng) { realPrintStream.print(ssortingng); logger.info(ssortingng); } }; } } 

Dans le code Skaffman: Pour supprimer les lignes vides des journaux de log4j, ajoutez simplement la méthode “println” à PrintStream de createLoggingProxy

 public static PrintStream createLoggingProxy(final PrintStream realPrintStream) { return new PrintStream(realPrintStream) { public void print(final Ssortingng ssortingng) { logger.warn(ssortingng); } public void println(final Ssortingng ssortingng) { logger.warn(ssortingng); } }; } 

J’ai repris l’idée de Michael S., mais comme mentionné dans un commentaire, cela pose quelques problèmes: il ne capture pas tout et imprime des lignes vides.

Je voulais également séparer System.out et System.err , afin que System.out soit consigné avec le niveau 'INFO' et que System.err soit consigné avec 'ERROR' (ou 'WARN' si vous voulez).

OutputStream donc ma solution: tout d’abord, une classe qui étend OutputStream (il est plus facile de remplacer toutes les méthodes pour OutputStream que pour PrintStream ). Il se connecte avec un niveau de journal spécifié et copie également tout dans un autre OutputStream . Et aussi, il détecte les chaînes “vides” (ne contenant que des espaces) et ne les enregistre pas.

 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); Ssortingng ssortingng = new Ssortingng(b); if (!ssortingng.sortingm().isEmpty()) logger.log(logLevel, ssortingng); } @Override public void write(byte[] b, int off, int len) throws IOException { outputStream.write(b, off, len); Ssortingng ssortingng = new Ssortingng(b, off, len); if (!ssortingng.sortingm().isEmpty()) logger.log(logLevel, ssortingng); } @Override public void write(int b) throws IOException { outputStream.write(b); Ssortingng ssortingng = Ssortingng.valueOf((char) b); if (!ssortingng.sortingm().isEmpty()) logger.log(logLevel, ssortingng); } } 

Et puis une classe d’utilitaire très simple pour définir et 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))); } } 

Si vous utilisez un serveur d’applications, un conteneur de servlets ou quelque chose de similaire, consultez la réponse de kgiannakakis .

Pour les applications autonomes voir ceci . Vous pouvez réinstaller stdin , stdout et stderr en utilisant la classe java.lang.System . Fondamentalement, vous créez une nouvelle sous-classe de PrintStream et définissez cette instance sur System.out.

Quelque chose dans ce sens au démarrage de votre application (non testé).

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

Je suppose que vous enregistrez des emstackments via e.printStackTrace() ? Vous pouvez passer un object d’exception dans les méthodes de journalisation Log4j et celles-ci apparaîtront dans votre journal (voir Logger.error (Object obj, Throwable t) )

Notez que vous pouvez changer System.out et System.err en un autre PrintStream qui redirige vers Log4j. Ce serait un changement simple et vous System.out.println() convertir toutes vos instructions System.out.println() .

Les réponses ci-dessus donnent une excellente idée d’utiliser le proxy pour la journalisation STDOUT / ERR. Cependant, les exemples d’implémentation fournis ne fonctionnent pas correctement pour tous les cas. Par exemple, essayez

System.out.printf (“Tester% s \ n”, “ABC”);

Le code des exemples ci-dessus va couper la sortie en morceaux séparés sur une console et dans plusieurs entrées Log4j non lisibles.

La solution consiste à mettre la sortie en mémoire tampon jusqu’à ce qu’un déclencheur soit trouvé à la fin du tampon. Parfois, le tampon se termine par ‘\ r \ n’. La classe ci-dessous aborde ce problème. Il est entièrement fonctionnel. Appelez la méthode statique bind () pour l’activer.

 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 SsortingngBuilder sbBuffer; public LoggerStream(Logger logger, Level logLevel, OutputStream outputStream) { this.logger = logger; this.logLevel = logLevel; this.outputStream = outputStream; sbBuffer = new SsortingngBuilder(); } @Override public void write(byte[] b) throws IOException { doWrite(new Ssortingng(b)); } @Override public void write(byte[] b, int off, int len) throws IOException { doWrite(new Ssortingng(b, off, len)); } @Override public void write(int b) throws IOException { doWrite(Ssortingng.valueOf((char)b)); } private void doWrite(Ssortingng 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' } Ssortingng buf = sbBuffer.toSsortingng(); sbBuffer.setLength(0); outputStream.write(buf.getBytes()); outputStream.write('\n'); logger.log(logLevel, buf); } } } // inner class LoggerStream } 

Les stream de sortie et d’erreur standard sont gérés à partir de votre conteneur. Par exemple, Tomcat utilise JULI pour consigner les stream de sortie et d’erreur.

Ma recommandation est de les laisser telles quelles. Évitez d’utiliser System.out.print dans votre application. Voir ici pour les traces de stack.

L’anser de @Michael est un bon point. Mais l’extension de PrintStream n’est pas très agréable, car elle utilise une méthode interne void write(Ssortingng) pour écrire toutes les choses dans un OutputStream.

Je préfère utiliser la classe LoggingOutputStream partir du package Log4J Consortingb.

Ensuite, je redirige les stream système comme ceci:

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

Avant d’utiliser la méthode System.setOut et System.setErr, vous devez réinitialiser l’object java.util.logging.LogManager en utilisant la méthode reset ().

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