2012-06-25 10 views
21

Avevo bisogno di reindirizzare gli output di System.out/err.println a slf4j.Reindirizzare System.out e System.err su slf4j

So che questo non è il modo di fare la registrazione correttamente ma c'è una libreria esterna, che registra a System.out

+0

googling rapida sulla questione mi ha dato la sua risposta, ma anche questo link che sembra interessante: http://projects.lidalia.org.uk/sysout-over-slf4j/index.html – remi

risposta

13

È possibile utilizzare sysout-over-slf4j.

Il modulo sysout-over-slf4j consente a un utente di reindirizzare tutte le chiamate a System.out e System.err a uno SLF4J logger definito con il nome della classe completo in cui lo System.out.println (o simili) è stata effettuata una chiamata, a livelli configurabili.

Se siete non usando Maven, download il vaso e aggiungerlo al classpath.

In alternativa, aggiungerlo come una dipendenza Maven:

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

Poi all'avvio dell'applicazione, call:

SysOutOverSLF4J.sendSystemOutAndErrToSLF4J(); 
+1

Sembra che sysout-ver-slf4j dipenda da slf4j 1.6.0 Ho provato ad aggiungerlo al nostro classpath e abbiamo errori di compilazione poiché stiamo usando slf4j 1.7.7 – pranahata

+1

Funziona perfettamente (slf4j 1.7.13) – Andrey

+0

Accettato come nuovo risponditore ! È meglio avere una biblioteca controllata invece di un codice di codice da qualcuno. Ma devo dire che non ho testato la libreria! – itshorty

19

ho risolto il problema utilizzando il LoggingOutputStream per log4j e modificato un po ' bit per 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; 
    } 
} 
} 

Ora è possibile reindirizzare Sytem.out/err chiamando SysStreamsLogger.bindSystemStreams() al all'inizio dell'applicazione.

registrazione dell'output assomiglia a questo (da avvio OpenEJB)

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

Utilizzato questo, ma ha aggiunto un System.getProperty() per afferrare un vm -DREDIRECT_SYSLOGS = true in modo che Eclipse registri ancora errori nella sua console come previsto. Ho solo reindirizzare i registri in un ambiente di produzione. – Kieveli

+0

N1, ma non thread-safe. –

+0

Grazie per aver condiviso questo .. Sono riuscito a reindirizzare il flusso di errori per il log. – Buminda