log4j는 stdout을 DailyRollingFileAppender로 리디렉션합니다.
log4j를 사용하는 자바 앱이 있습니다.
구성 :
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이 손실됩니다. 예외 스택 추적 및 sysout을 매일 롤링 된 파일로 리디렉션하려면 어떻게합니까?
// 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);
}
};
}
}
Skaffman 코드에서 : log4j 로그에서 빈 줄을 제거하려면 createLoggingProxy의 PrintStream에 "println"메서드를 추가하면됩니다.
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);
}
};
}
나는 Michael S.로부터 아이디어를 얻었지만 한 댓글에서 언급했듯이 몇 가지 문제가 있습니다. 모든 것을 캡처하지 않고 빈 줄을 인쇄합니다.
또한 나는 분리하고 싶어 System.out
하고 System.err
그 때문에, System.out
로그 수준으로 기록됩니다 'INFO'
와 System.err
함께 기록됩니다 'ERROR'
(또는 'WARN'
당신이 좋아하는 경우).
그래서 이것은 내 해결책입니다 : 먼저 확장되는 클래스 OutputStream
(for 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의 답변을 참조하십시오 .
독립형 앱의 경우 이를 참조 하십시오 . java.lang.System 클래스를 사용하여 stdin , stdout 및 stderr 을 다시 지정할 수 있습니다 . 기본적으로 PrintStream의 새 하위 클래스를 만들고 해당 인스턴스를 System.out으로 설정합니다.
앱 시작에서이 라인을 따라있는 것 (예정되지 않음).
// 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());
위의 답변은 STDOUT / ERR 로깅에 프록시를 사용하는 훌륭한 아이디어를 제공합니다. 그러나 제공된 구현 예제는 모든 경우에 잘 작동하지 않습니다. 예를 들어
System.out.printf ( "% s 테스트 중 \ n", "ABC");
위 예제의 코드는 출력을 콘솔 및 읽을 수없는 여러 Log4j 항목에서 개별 조각으로 잘라냅니다.
해결책은 버퍼 끝에서 트리거 '\ n'을 찾을 때까지 출력을 버퍼링하는 것입니다. 때때로 버퍼는 '\ r \ n'으로 끝납니다. 아래 클래스는이 문제를 해결합니다. 완벽하게 작동합니다. 활성화하려면 정적 메소드 bind ()를 호출하십시오.
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
}
을 통해 스택 추적을 로깅한다고 가정합니다 e.printStackTrace()
. 예외 객체를 Log4j 로깅 메서드에 전달할 수 있으며 로그에 표시됩니다 ( Logger.error (Object obj, Throwable t) 참조 ).
System.out 및 System.err 을 Log4j로 리디렉션하는 다른 PrintStream으로 변경할 수 있습니다 . 그것은 간단한 변경이며 모든 System.out.println()
진술 을 변환하는 것을 절약 할 수 있습니다 .
표준 출력 및 오류 스트림은 컨테이너에서 관리됩니다. 예를 들어 Tomcat은 JULI를 사용하여 출력 및 오류 스트림을 기록합니다.
My recommendation is to leave these as it is. Avoid using System.out.print in your application. See here for stack traces.
The anser of @Michael is a good Point. But extending PrintStream is not very nice, because it uses a internal method void write(String)
to write all things to an OutputStream.
I prefer to use the LoggingOutputStream
Class from the Log4J Contrib package.
Then i redirect the system-streams like this:
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);
}
}
Before using the System.setOut and System.setErr method we should reset the java.util.logging.LogManager object by using 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();
}
}
참고URL : https://stackoverflow.com/questions/1200175/log4j-redirect-stdout-to-dailyrollingfileappender
'Program Tip' 카테고리의 다른 글
새 Google Recaptcha (v2) 너비 변경 (0) | 2020.11.20 |
---|---|
자바로 웹 사이트를 어떻게 만드나요? (0) | 2020.11.20 |
JavaScript를 사용하여 ID가있는 td에 텍스트를 삽입하는 방법 (0) | 2020.11.20 |
REPL에서 Clojure 버전을 표시하는 방법은 무엇입니까? (0) | 2020.11.20 |
파일 핸들을 사용하여 파일 이름 가져 오기 (또는 파일 삭제) (0) | 2020.11.20 |