к log4j перенаправить стандартный вывод в DailyRollingFileAppender
У меня есть java-приложение, которое использует 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
таким образом, все операторы журнала правильно добавляются в файл, но я теряю stdout и stderr. Как перенаправить трассировки стека исключений и sysouts в ежедневный свернутый файл ?
9 ответов:
// 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); } }; } }
в коде Скаффмана: чтобы удалить пустые строки в журналах log4j, просто добавьте метод "println" в 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); } }; }
я взял идею от Майкла С., Но, как упоминалось в одном комментарии, у него есть некоторые проблемы: он не захватывает все, и он печатает некоторые пустые строки.
также я хотел отделить
System.out
иSystem.err
, Так чтоSystem.out
регистрируется с уровнем журнала'INFO'
иSystem.err
войти с'ERROR'
(или'WARN'
если вам нравится).так что это мое решение: Первый класс, который расширяет
OutputStream
(проще переопределить все методыOutputStream
чем дляPrintStream
). Он регистрируется с указанным уровнем журнала, а также копирует все на другойOutputStream
. А также он обнаруживает "пустые" строки (содержащие только пробелы) и не регистрирует их.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); } }
и затем очень простой класс утилиты для установки
out
и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))); } }
Если вы используете сервер приложений, сервлетов контейнер или что-то подобное, см. kgiannakakis это.
для автономных приложений см. этой. Вы можете reassing stdin,stdout и stderr используя java.ленг.Система класса. В основном вы создаете новый подкласс PrintStream и устанавливаете этот экземпляр в System.из.
что-то в этом роде в начале вашего приложения (непроверенный.)
// 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());
Я предполагаю, что вы регистрируете stacktraces через
e.printStackTrace()
? Вы можете передать объект исключения в методы ведения журнала Log4j, и они появятся в вашем журнале (см. регистратор.ошибка (объект obj, Throwable t))обратите внимание, что вы можете изменить систему.и системы.подстраховаться в другой PrintStream, который перенаправляет к log4j. Это будет простой изменить и спасти вам преобразовывать все ваши
System.out.println()
заявления.
ответы выше дают отличную идею использовать прокси для ведения журнала STDOUT/ERR. Однако приведенные примеры реализации не работают хорошо для всех случаев. Например, попробовать
стандартные потоки вывода и ошибок управляются из вашего контейнера. Например, Tomcat использует JULI для регистрации выходных данных и потоков ошибок.
моя рекомендация-оставить их как есть. Избегайте использования системы.из.печать в вашем приложении. Смотрите здесь для трассировки стека.
Ансер @Michael-это хороший момент. Но расширение PrintStream не очень приятно, потому что он использует внутренний метод
void write(String)
чтобы записать все вещи в выходной поток.Я предпочитаю использовать
LoggingOutputStream
класс из пакета log4j Contrib.затем я перенаправляю системные потоки следующим образом:
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); } }
перед использованием системы.установка и система.метод setErr мы должны сбросить java.утиль.лесозаготовительный.Объект LogManager с помощью метода 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(); } }