red.4

2012-06-25 14 views
21

पर System.out और System.err को रीडायरेक्ट करें। मुझे system.out/err.println outputs को slf4j पर रीडायरेक्ट करने की आवश्यकता है।red.4

मुझे पता है कि इस तरह से ठीक से प्रवेश करने करने के लिए नहीं है, लेकिन वहाँ एक बाहरी पुस्तकालय, जो

+0

कि इस मामले पर त्वरित Googling मुझे अपने जवाब पर भी इस लिंक जो दिलचस्प लगता दिया: http://projects.lidalia.org.uk/sysout-over-slf4j/index.html – remi

उत्तर

13

sysout-ओवर-slf4j मॉड्यूल एक SLF4J पूरी तरह से योग्य वर्ग के नाम के साथ परिभाषित लकड़हारा को System.out और System.err के लिए सभी कॉल पुनर्निर्देशित करने के लिए एक उपयोगकर्ता की अनुमति देता है, जिसमें println (या इसी तरह) कॉल कॉन्फ़िगर करने योग्य स्तर पर बनाया गया था।

यदि आप हैं नहीं Maven का उपयोग कर, download जार और अपने classpath में जोड़ें।

<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

मैं log4j के लिए LoggingOutputStream का उपयोग करके समस्या को हल करने के लिए 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/अं रीडायरेक्ट करने के लिए संभव है।

लॉगिंग आउटपुट (OpenEJB स्टार्टअप से) आप 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

एन 1, लेकिन धागा-सुरक्षित नहीं। –

+0

इसे साझा करने के लिए धन्यवाद .. मैं लॉग स्ट्रीम करने के लिए त्रुटि स्ट्रीम को पुनर्निर्देशित करने में कामयाब रहा। – Buminda