문제

log4J를 사용하는 Java 앱이 있습니다.

구성 :

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를 Daily Rolled 파일로 어떻게 리디렉션합니까?

도움이 되었습니까?

해결책

// 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 (모든 방법을 재정의하는 것이 더 쉽습니다 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의 대답.

독립형 앱은 참조하십시오 이것. 당신은 안심할 수 있습니다 Stdin, stdout 그리고 Stderr 사용 java.lang.system 수업. 기본적으로 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'으로 끝납니다. 아래 수업은이 문제를 다룹니다. 완전히 기능적입니다. 정적 메소드 바인드 ()을 호출하여 활성화하십시오.

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로 리디렉션됩니다. 그것은 간단한 변화가 될 것이며 당신의 모든 것을 당신의 모든 변환을 절약 할 수 있습니다. System.out.println() 진술.

표준 출력 및 오류 스트림은 컨테이너에서 관리됩니다. 예를 들어 Tomcat은 Juli를 사용하여 출력 및 오류 스트림을 기록합니다.

내 추천은 이것을 그대로 두는 것입니다. 애플리케이션에서 System.out.print를 사용하지 마십시오. 보다 여기 스택 추적 용.

@Michael의 Anser는 좋은 지적입니다. 그러나 인쇄물을 확장하는 것은 내부 방법을 사용하기 때문에 그리 좋지 않습니다. 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);
    }
}

System.Setout 및 System.SetERR 메소드를 사용하기 전에 Reset () 메소드를 사용하여 java.util.logging.logmanager 객체를 재설정해야합니다.

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();
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top