2012-06-25 5 views
21

System.out/err.println 출력을 slf4j로 리디렉션해야했습니다.System.out 및 System.err을 slf4j로 리디렉션

나는이 제대로를 기록 할 수있는 방법이 아니라는 것을 알고 있지만 내가 log4j에 대한 LoggingOutputStream를 사용하여 문제를 해결

+0

빠른 인터넷 검색이 저에게 당신의 대답뿐만 아니라 흥미로운 것 같습니다이 링크를 준 : http://projects.lidalia.org.uk/sysout-over-slf4j/index.html – remi

답변

13

(OpenEJB를 시작에서) 다음과 같습니다.

SYSOUT 대비 SLF4J 모듈은 완전한 클래스의 이름 로거를 정의 된 SLF4J에 System.out에와 System.err에 대한 모든 호출을 리디렉션 사용자를 허용하는의에서 System.out.println (또는 이와 유사한) 호출이 구성 가능한 수준에서 이루어졌습니다.

당신은 메이븐을 사용 하지, download 항아리와 클래스 패스에 추가 인 경우. 응용 프로그램 시작시 다음

<dependency> 
    <groupId>uk.org.lidalia</groupId> 
    <artifactId>sysout-over-slf4j</artifactId> 
    <version>1.0.2</version> 
</dependency> 

, call :

또는 메이븐 의존성으로 추가

SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(); 
그 문제에
+1

보이는 sysout-ver-slf4j는 slf4j 1.6.0에 의존합니다. 클래스 패스에 추가하려고했습니다. slf4j를 사용하면서 컴파일 타임 오류가 발생했습니다. 1.7.7 – pranahata

+1

완벽하게 작동합니다 (slf4j 1.7.13) – Andrey

+0

새로운 답변으로 받아 들여집니다 ! 누군가의 코드 조각 대신에 maintaned 라이브러리를 갖는 것이 좋습니다. 그러나 나는 도서관을 시험하지 않았다는 것을 언급 할 필요가있다. – itshorty

19

System.out에 할 로그 외부 라이브러리가 존재하고 그것을 조금 수정 slf4j에 대한 비트.

import java.io.IOException; 
import java.io.PrintStream; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

public class SysStreamsLogger { 
private static Logger sysOutLogger = LoggerFactory.getLogger("SYSOUT"); 
private static Logger sysErrLogger = LoggerFactory.getLogger("SYSERR"); 

public static final PrintStream sysout = System.out; 
public static final PrintStream syserr = System.err; 

protected static final String LINE_SEPERATOR = System.getProperty("line.separator"); 

public static void bindSystemStreams() { 
    // Enable autoflush 
    System.setOut(new PrintStream(new LoggingOutputStream(sysOutLogger, false), true)); 
    System.setErr(new PrintStream(new LoggingOutputStream(sysErrLogger, true), true)); 
} 

public static void unbindSystemStreams() { 
    System.setOut(sysout); 
    System.setErr(syserr); 
} 

private static class LoggingOutputStream extends java.io.OutputStream { 

    protected Logger log; 
    protected boolean isError; 

    /** 
    * Used to maintain the contract of {@link #close()}. 
    */ 
    protected boolean hasBeenClosed = false; 

    /** 
    * The internal buffer where data is stored. 
    */ 
    protected byte[] buf; 

    /** 
    * The number of valid bytes in the buffer. This value is always in the 
    * range <tt>0</tt> through <tt>buf.length</tt>; elements 
    * <tt>buf[0]</tt> through <tt>buf[count-1]</tt> contain valid byte 
    * data. 
    */ 
    protected int count; 

    /** 
    * Remembers the size of the buffer for speed. 
    */ 
    private int bufLength; 

    /** 
    * The default number of bytes in the buffer. =2048 
    */ 
    public static final int DEFAULT_BUFFER_LENGTH = 2048; 

    private LoggingOutputStream() { 
     // illegal 
    } 

    /** 
    * Creates the LoggingOutputStream to flush to the given Category. 
    * 
    * @param log 
    *   the Logger to write to 
    * 
    * @param isError 
    *   the if true write to error, else info 
    * 
    * @exception IllegalArgumentException 
    *    if cat == null or priority == null 
    */ 
    public LoggingOutputStream(Logger log, boolean isError) throws IllegalArgumentException { 
     if (log == null) { 
      throw new IllegalArgumentException("log == null"); 
     } 

     this.isError = isError; 
     this.log = log; 
     bufLength = DEFAULT_BUFFER_LENGTH; 
     buf = new byte[DEFAULT_BUFFER_LENGTH]; 
     count = 0; 
    } 

    /** 
    * Closes this output stream and releases any system resources 
    * associated with this stream. The general contract of 
    * <code>close</code> is that it closes the output stream. A closed 
    * stream cannot perform output operations and cannot be reopened. 
    */ 
    @Override 
    public void close() { 
     flush(); 
     hasBeenClosed = true; 
    } 

    /** 
    * Writes the specified byte to this output stream. The general contract 
    * for <code>write</code> is that one byte is written to the output 
    * stream. The byte to be written is the eight low-order bits of the 
    * argument <code>b</code>. The 24 high-order bits of <code>b</code> are 
    * ignored. 
    * 
    * @param b 
    *   the <code>byte</code> to write 
    */ 
    @Override 
    public void write(final int b) throws IOException { 
     if (hasBeenClosed) { 
      throw new IOException("The stream has been closed."); 
     } 

     // don't log nulls 
     if (b == 0) { 
      return; 
     } 

     // would this be writing past the buffer? 
     if (count == bufLength) { 
      // grow the buffer 
      final int newBufLength = bufLength + DEFAULT_BUFFER_LENGTH; 
      final byte[] newBuf = new byte[newBufLength]; 

      System.arraycopy(buf, 0, newBuf, 0, bufLength); 

      buf = newBuf; 
      bufLength = newBufLength; 
     } 

     buf[count] = (byte) b; 
     count++; 
    } 

    /** 
    * Flushes this output stream and forces any buffered output bytes to be 
    * written out. The general contract of <code>flush</code> is that 
    * calling it is an indication that, if any bytes previously written 
    * have been buffered by the implementation of the output stream, such 
    * bytes should immediately be written to their intended destination. 
    */ 
    @Override 
    public void flush() { 

     if (count == 0) { 
      return; 
     } 

     // don't print out blank lines; flushing from PrintStream puts out 
     // these 
     if (count == LINE_SEPERATOR.length()) { 
      if (((char) buf[0]) == LINE_SEPERATOR.charAt(0) && ((count == 1) || // <- 
                       // Unix 
                       // & 
                       // Mac, 
                       // -> 
                       // Windows 
        ((count == 2) && ((char) buf[1]) == LINE_SEPERATOR.charAt(1)))) { 
       reset(); 
       return; 
      } 
     } 

     final byte[] theBytes = new byte[count]; 

     System.arraycopy(buf, 0, theBytes, 0, count); 

     if (isError) { 
      log.error(new String(theBytes)); 
     } else { 
      log.info(new String(theBytes)); 
     } 

     reset(); 
    } 

    private void reset() { 
     // not resetting the buffer -- assuming that if it grew that it 
     // will likely grow similarly again 
     count = 0; 
    } 
} 
} 

는 이제 응용 프로그램의 시작에 SysStreamsLogger.bindSystemStreams()를 호출하여 Sytem.out/ERR 리디렉션 할 수 있습니다. 당신은 sysout-over-slf4j을 사용할 수 있습니다

로그 출력

2012-06-27 13:44:12,792 INFO [main:] SYSOUT:181 - Apache OpenEJB 3.1.4 build: 20101112-03:32 
2012-06-27 13:44:12,793 INFO [main:] SYSOUT:181 - http://openejb.apache.org/ 
+0

사용되었지만 vm -DREDIRECT_SYSLOGS = true를 잡아내는 System.getProperty()를 추가하여 이클립스가 여전히 콘솔에 오류를 기록하도록합니다. 예상대로 프로덕션 환경에서만 로그를 리디렉션합니다. – Kieveli

+0

N1 (스레드로부터 안전하지 않음) –

+0

공유 해 주셔서 감사합니다. 오류 스트림을 로그로 리디렉션 할 수있었습니다. – Buminda