2009-07-29 15 views
56

पर stdout को रीडायरेक्ट करें मेरे पास एक जावा ऐप है जो log4j का उपयोग करता है।log4j DailyRollingFileAppender

कॉन्फ़िग:

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 को पुनर्निर्देशित कैसे करूं?

उत्तर

88
// 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); 
      } 
     }; 
    } 
} 
+7

यह अपवादों के साथ काम करता है, लेकिन यह stdout पर लिखे गए सभी आउटपुट को कैप्चर नहीं करता है। उदाहरण के लिए यदि आपने System.out.print (5) कहा है; यह प्रॉक्सी प्रिंट स्ट्रीम को बाईपास करेगा। साथ ही, अपवादों के साथ भी अगर आप कुछ अपवाद करते हैं तो यह अतिरिक्त रिक्त रेखाओं को मुद्रित कर देगा .printStackTrace() – sbridges

+0

हाय .. जहां लॉग फ़ाइल उत्पन्न होगी? धन्यवाद –

+3

@ एसब्रिजेस यदि आपको आवश्यकता हो तो आप अधिक तरीकों को ओवरराइड कर सकते हैं। उदाहरण के लिए 'printStackTrace'' println (ऑब्जेक्ट ओ) 'विधि को कॉल करता है जिसे आप उन खराब रिक्त रेखाओं को खत्म करने के लिए ओवरराइड भी कर सकते हैं। – tysonjh

2

मुझे लगता है कि आप e.printStackTrace() के माध्यम से stacktraces लॉगिंग कर रहे हैं? आप log4j प्रवेश तरीकों में एक अपवाद वस्तु पारित कर सकते हैं और उन अपनी लॉग में दिखाई देगा (देखें Logger.error(Object obj, Throwable t))

ध्यान दें कि यदि आप किसी अन्य PrintStream कि log4j पर रीडायरेक्ट करने के लिए System.out और System.err बदल सकते हैं। यह एक सीधा बदलाव होगा और आपको अपने सभी System.out.println() कथनों को परिवर्तित करने में मदद करेगा।

1

मानक आउटपुट और त्रुटि स्ट्रीम आपके कंटेनर से प्रबंधित की जाती हैं। उदाहरण के लिए टॉमकैट आउटपुट और त्रुटि स्ट्रीम लॉग करने के लिए जुली का उपयोग करता है।

मेरी सिफारिश इन्हें छोड़ने के लिए है। अपने आवेदन में System.out.print का उपयोग करने से बचें। स्टैक निशान के लिए here देखें।

+0

स्टैंडअलोन जावा ऐप्स के बारे में कैसे एक कंटेनर का उपयोग नहीं करते हैं? निश्चित रूप से stdout पकड़ने और log4j पर लॉग इन करने का एक तरीका है? –

+0

ब्रायन एग्नेव द्वारा सुझाए गए अनुसार आप स्ट्रीम को log4j पर रीडायरेक्ट कर सकते हैं। हालांकि मैं इसके खिलाफ सिफारिश करता हूं। समाधान मानक आउटपुट पर प्रिंट नहीं करना है, बल्कि इसके बजाय log4j का उपयोग करें। मानक आउटपुट का उपयोग करने वाली एक सभ्य जावा लाइब्रेरी नहीं है। यदि आपके पास तीसरा पक्ष कोड है जो ऐसा करता है, तो उन्हें log4j या कॉमन्स लॉगिंग का उपयोग करने के लिए कहें। मानक आउटपुट को पुनर्निर्देशित करना अंतिम उपाय होना चाहिए। – kgiannakakis

+0

लॉगिंग के लिए System.out.println() का उपयोग न करें। अपने कोड में log4j (या कोई अन्य लॉगिंग फ्रेमवर्क) का प्रयोग करें, और बस कॉन्फ़िगरेशन को आउटपुट को stdout पर भेजें। –

5

यदि आप एक एप्लिकेशन सर्वर, सर्वलेट कंटेनर या कुछ समान उपयोग कर रहे हैं, तो kgiannakakis's answer देखें।

स्टैंडअलोन ऐप्स के लिए this देखें। आप java.lang.System कक्षा का उपयोग कर stdin, stdout और stderr को पुन: प्राप्त कर सकते हैं। असल में आप प्रिंटस्ट्रीम का एक नया उप-वर्ग बनाते हैं और उस उदाहरण को 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()); 
7

मैं माइकल एस से विचार उठाया है, लेकिन जैसे एक टिप्पणी में उल्लेख किया है, यह कुछ समस्याओं का है: यह सब कुछ पर कब्जा नहीं है, और यह कुछ खाली लाइनों प्रिंट करता है।

इसके अलावा, मैं System.out और System.err अलग करने के लिए है, ताकि System.out लॉग स्तर 'INFO' साथ लॉग होता है और System.err'ERROR' साथ लॉग होता है (या 'WARN' यदि आप चाहें) चाहता था। सबसे पहले एक वर्ग है कि OutputStream फैली (यह PrintStream के लिए की तुलना में OutputStream के लिए सभी तरीकों ओवरराइड करने के लिए आसान है):

तो यह मेरा समाधान है। यह एक निर्दिष्ट लॉग स्तर के साथ लॉग करता है और यह सब कुछ 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))); 
} 

} 
+0

लॉग फ़ाइल में पथ जोड़ने के लिए कहां ?? – Aniket

+0

क्या आप मुझे इस बारे में एक विचार दे सकते हैं कि log4j.properties या log4j.xml फ़ाइल को यह काम करने के लिए कैसा दिखना चाहिए? – Aniket

+0

@acoolguy देखें [लॉग 4j एक्सएमएल कॉन्फ़िगरेशन प्राइमर] (http: //wiki.apache।संगठन/लॉगिंग-लॉग 4j/log4jXmlFormat), एक [FileAppender] (http://wiki.apache.org/logging-log4j/FileAppender) का उपयोग करें। –

1

@Michael की anser एक अच्छा प्वाइंट है। लेकिन प्रिंटस्ट्रीम का विस्तार करना बहुत अच्छा नहीं है, क्योंकि यह आउटपुटस्ट्रीम में सभी चीजों को लिखने के लिए आंतरिक विधि void write(String) का उपयोग करता है।

मैं Log4J Contrib पैकेज से LoggingOutputStream Class का उपयोग करना पसंद करता हूं।

तो मैं इस तरह प्रणाली धाराओं अनुप्रेषित:

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); 
    } 
} 
+0

लॉगिंगऑटपुटस्ट्रीम अब नवीनतम लॉग 4j contrib रिलीज (1.0.4) –

+0

में मौजूद नहीं प्रतीत होता है बस इसे https://svn.apache.org/viewvc/logging से लें /log4j/trunk/contribs/JimMoore/LoggingOutputStream.java?view=co! यह अकेले सुंदर खड़ा है। – itshorty

10

Skaffman कोड में: log4j लॉग में खाली लाइनों को हटाने के लिए, बस createLoggingProxy

की
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); 
     } 
    }; 
} 
2

PrintStream में जोड़ें "println" विधि ऊपर दिए गए उत्तरों STDOUT/ERR लॉगिंग के लिए प्रॉक्सी का उपयोग करने के लिए एक उत्कृष्ट विचार देते हैं। हालांकि प्रदान किया गया कार्यान्वयन उदाहरण सभी मामलों के लिए अच्छी तरह से काम नहीं करते हैं। उदाहरण के लिए,

System.out.printf ("परीक्षण% s \ n", "एबीसी") का प्रयास करें;

उपर्युक्त उदाहरणों से कोड आउटपुट को कंसोल पर अलग-अलग टुकड़ों में और कई पठनीय लॉग 4j प्रविष्टियों में कटौती नहीं करेगा।

समाधान तब तक आउटपुट बफर करना है जब तक कि ट्रिगर '\ 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 

} 
0

System.setOut और System.setErr विधि का उपयोग कर इससे पहले कि हम रीसेट() विधि का उपयोग कर 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(); 
    } 
}