2012-06-25 23 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モジュールは、ユーザがその中のSystem.out.printlnは(完全修飾されたクラスの名前で定義されたSLF4JロガーにSystem.outおよびSystem.errにすべてのコールをリダイレクトすることができまたは類似の)呼が構成可能なレベルで行われた。

あなたはMavenを使用してないdownload瓶とあなたのクラスパスに追加がある場合。アプリケーションの起動時に次に

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

call

また、Mavenの依存関係として追加

SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(); 
そのことに
+1

sysout-ver-slf4jはslf4jに依存1.6.0私はクラスパスに追加しようとしましたが、slf4jを使用しているのでコンパイル時エラーが発生しました1.7.7 – pranahata

+1

完全にうまく動作します(slf4j 1.7.13) – Andrey

+0

新しい回答者として受け入れられる!誰かからのコードではなく、メインテナンスされたライブラリを持つ方がよいでしょう。しかし、私はライブラリをテストしていないことに言及する必要があります! – 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

これを使用しましたが、System.getProperty()を追加してvm-GREDIRECT_SYSLOGS = trueを取得し、Eclipseがコンソールにエラーを記録するようにしました予想通り。私は運用環境でのみログをリダイレクトします。 – Kieveli

+0

N1ですが、スレッドセーフではありません。 –

+0

これを共有していただきありがとうございます。エラーストリームをログにリダイレクトすることができました。 – Buminda