2013-01-18 13 views
6

मैं एक स्प्रिंग 3.1.1 में लॉग 4j 1.2.15 का उपयोग कर रहा हूं। जेबॉस एएस 7.1.1.इनल पर तैनात किया गया एप्लिकेशन। मैं log4j में लिखित आउटपुट को मेरी प्रतिक्रिया आउटपुट स्ट्रीम में रूट करने की कोशिश कर रहा हूं। मैं उत्पादन इसमैं अपने HttpServletResponse आउटपुट स्ट्रीम में log4j आउटपुट को रीडायरेक्ट कैसे करूं?

private static final Logger LOG = Logger.getLogger(TrainingSessionServiceImpl.class); 
… 
LOG.info("Creating/updating training session associated with order #:" + order.getId()); 

की तरह लिखा है और मैं बहुत तरह मेरे उत्पादन स्ट्रीम पर रूट करने के लिए

@RequestMapping(value = "/refreshPd", method = RequestMethod.GET) 
public void refreshPD(final HttpServletResponse response) throws IOException 
{ 
    ...   
    final WriterAppender appender = new WriterAppender(new PatternLayout("%d{ISO8601} %p - %m%n"),response.getWriter()); 
    appender.setName("CONSOLE_APPENDER"); 
    appender.setThreshold(org.apache.log4j.Level.DEBUG); 
    Logger.getRootLogger().addAppender(appender); 

    worker.work(); 

    Logger.getRootLogger().removeAppender("CONSOLE_APPENDER"); 

भले ही मैं जानता हूँ कि कोशिश कर रहा हूँ ... लेकिन दुर्भाग्य से, कुछ भी अपने ब्राउज़र के लिए उत्पादन हो रही है, (डीबगिंग के माध्यम से) कि लॉगिंग स्टेटमेंट बुलाया जा रहा है। क्या कोई जानता है कि मैं इसे कैसे काम करने के लिए अपने सेटअप को समायोजित कर सकता हूं? नीचे मेरी log4j.properties फ़ाइल है, जो मेरे युद्ध की वेब-आईएनएफ/कक्षा निर्देशिका में तैनात है।

log4j.rootLogger=DEBUG, CA, FA 

#Console Appender 
log4j.appender.CA=org.apache.log4j.ConsoleAppender 
log4j.appender.CA.layout=org.apache.log4j.PatternLayout 
log4j.appender.CA.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n 

#File Appender 
log4j.appender.FA=org.apache.log4j.FileAppender 
log4j.appender.FA.File=/usr/java/jboss/server/default/log/log4j.log 
log4j.appender.FA.layout=org.apache.log4j.PatternLayout 
log4j.appender.FA.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n 

# Set the logger level of File Appender to WARN 
log4j.appender.FA.Threshold = DEBUG 

धन्यवाद, - डेव

+0

क्या 'worker.work()' समान या अन्य धागे में चलता है? समस्या से पता चलता है कि यह एक और धागे में चलता है। – BalusC

+0

हां, यह एक ही धागे में चलता है। – Dave

+0

टॉमकैट पर मेरे लिए ठीक काम करता है। थोड़ी सी जांच के बाद, यह जेबॉस एएस विशिष्ट मुद्दे की तरह दिखता है: http://stackoverflow.com/questions/6071809/adding-log4j-appenders- प्रोग्रामेटिक रूप से और बाद में https://issues.jboss.org/browse/JBAS-9318 – BalusC

उत्तर

7

यह एक दिलचस्प समस्या थी। मुख्य बात यह है कि आप अपना खुद का एपेंडर लिखें। मैंने प्रेरणा के लिए बनाया org.apache.log4j.ConsoleAppender कोड बनाया। मैंने इसे अपने टोमकैट में परीक्षण किया है और सत्यापित किया है कि यह काम करता है। मैंने log4j-1.2 का उपयोग किया।17 (उम्मीद है कि कोई फर्क नहीं पड़ता)

1) सबसे पहले अपने स्वयं के एपेंडर को लागू करें। यह appender वर्तमान थ्रेड outputstream

package com.tstwbprj.log; 

import org.apache.log4j.Layout; 
import org.apache.log4j.WriterAppender; 

import java.io.IOException; 
import java.io.OutputStream; 

public class HttpLogAppender extends WriterAppender { 

    static ThreadLocal<OutputStream> streamPerHttpThread = new ThreadLocal<OutputStream>(); 

    public HttpLogAppender() { 

    } 

    public HttpLogAppender(Layout layout) { 
     setLayout(layout);  //super-class method 
     activateOptions(); 
    } 

    public void setCurrentHttpStream(OutputStream stream) { 
     streamPerHttpThread.set(stream); 
    } 


    public void activateOptions() { 
     setWriter(createWriter(new CurrentHttpThreadOutStream())); 
    } 


    /** 
    * An implementation of OutputStream that redirects to the 
    * current http threads servlet output stream 
    */ 
    private static class CurrentHttpThreadOutStream extends OutputStream { 
     public CurrentHttpThreadOutStream() { 
     } 

     public void close() { 
     } 

     public void flush() throws IOException { 
      OutputStream stream = streamPerHttpThread.get(); 
      if (stream != null) { 
       stream.flush(); 
      } 
     } 

     public void write(final byte[] b) throws IOException { 
      OutputStream stream = streamPerHttpThread.get(); 
      if (stream != null) { 
       stream.write(b); 
      } 
     } 

     public void write(final byte[] b, final int off, final int len) 
       throws IOException { 
      OutputStream stream = streamPerHttpThread.get(); 
      if (stream != null) { 
       stream.write(b, off, len); 
      } 
     } 

     public void write(final int b) throws IOException { 
      OutputStream stream = streamPerHttpThread.get(); 
      if (stream != null) { 
       stream.write(b); 
      } 
     } 
    } 
} 

2) करने के लिए सभी लॉग ईवेंट को लिखेंगे सिर्फ अन्य सेटिंग्स

log4j.rootLogger = डीबग, सीए, एफए, हा की तरह अपने log4j विन्यास फाइल में इस appender जोड़े
..
log4j.appender.HA = com.tstwbprj.log.HttpLogAppender log4j.appender.HA.layout = org.apache.log4j.PatternLayout log4j.appender.HA.layout.ConversionPattern =% - 4 आर [% टी]% -5 पी % सी% एक्स -% एम% एन

3) अपने सर्वलेट में कोड का एक छोटा सा टुकड़ा जोड़ें ताकि यह एपेंडर सही तरीके से काम कर सके। यहाँ मेरा सर्वलेट है।

import org.apache.log4j.Category; 
import org.apache.log4j.Logger; 
import javax.servlet.ServletOutputStream; 
import java.io.IOException; 

public class LogServlet extends javax.servlet.http.HttpServlet { 

    private static final Logger LOG = Logger.getLogger(LogServlet.class); 

    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { 

    } 

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { 
     ServletOutputStream outstream = response.getOutputStream(); 
     configureLogForCurrentRequest(outstream); 

     LOG.info("Got request");//this is now send to the servlet output stream !! 
     LOG.info("Hello!!"); 
     LOG.info("Done!!"); 
    } 

    private void configureLogForCurrentRequest(ServletOutputStream outstream) { 

     HttpLogAppender appender = (HttpLogAppender) LOG.getAppender("HA"); 
     while (appender == null) { 
      Category parent = LOG.getParent(); 
      if (parent == null) { 
       break; //This ideally shouldn't happen. Navigated all the way to root logger and still did not find appender !!..something wrong with log4j configuration setup 
      } 
      appender = (HttpLogAppender) parent.getAppender("HA"); 

     } 
     appender.setCurrentHttpStream(outstream); 
    } 
} 

सावधानी: यह अच्छी तरह से कई सर्वलेट अनुरोध आदि के साथ विशेष रूप से परीक्षण नहीं किया गया है इसके अलावा नहीं यकीन है कि तुम क्यों ऐसा करना चाहते हैं। यह ब्राउज़र पर पाइप लॉग संदेशों के लिए विशिष्ट नहीं है। सावधानी के साथ आगे बढ़ें ..:) -

+0

हाय, मुझे "appender.setCurrentHttpStream (आउटस्ट्रीम)" पर एक NullPointerException मिल रहा है; "। मैंने देखा कि जब "HttpLogAppender appender = (HttpLogAppender) LOG.getAppender (" HA ");" कहा जाता है, एपेंडर भी शुरू में शून्य है। आप "configLogForCurrentRequest" के साथ क्या करने का प्रयास कर रहे हैं? – Dave

+0

HttpLogAppender को आपके रूट लॉगर से जोड़ा जाना चाहिए यदि आपकी log4j.properties सही तरीके से सेटअप है ... यह उस पहली पंक्ति में शून्य होगी। यह है कि हमारे पास रूट लॉगर से पुनर्प्राप्त करने के लिए लॉगर पदानुक्रम को ऊपर जाने के लिए थोड़ी देर लूप क्यों है। एक बार HttpLogAppender को पुनर्प्राप्त करने के बाद, हम इसे वर्तमान सर्वलेट्स की प्रतिक्रिया आउटपुटस्ट्रीम पास करते हैं ताकि किसी भी लॉगिंग ईवेंट को – Zenil

+1

पर लिखा जा सके। मैंने पाया कि जेबॉस एक पेन सेंट रक्षात्मक समन्वयक से लॉग 4j से भी खराब है - http://stackoverflow.com/questions/9584787/का उपयोग कर-log4j-साथ-jboss-7-1। एक बार जब मैंने उस तैनाती संरचना फ़ाइल को जोड़ा, तो आप समाधान काम कर रहे हैं। धन्यवाद, - – Dave

0

मैं वैकल्पिक दृष्टिकोण लेने के लिए और लोग इन अलग ब्राउज़र टैब पर फ़ाइल सामग्री लाने का सुझाव देते हैं।

इसे मुख्य कोड संशोधन की आवश्यकता नहीं होगी और मूल पृष्ठ के स्वरूपण को नष्ट नहीं करेगा।

कुछ वेब आधारित लॉग फ़ाइल दर्शकों लिंक:

1

कुछ इस तरह के साथ प्रयास करें:

Logger logger = Logger.getRootLogger(); 
String name = "myAppender"; 

Appender servletAppender = logger.getAppender(appenderName); 
OutputStream out = response.getOutputStream(); 

if (servletAppender == null) { 
    servletAppender = new WriterAppender(new PatternLayout("%d{ISO8601} %p - %m%n"), out); 
    servletAppender.setName(appenderName); 
    appender.setThreshold(org.apache.log4j.Level.DEBUG); 
    logger.addAppender(servletAppender); 
} 

try { 
    // Your work 
    worker.work(); 
} finally { 
    logger.removeAppender(appenderName); 
    out.flush(); 
} 
+0

org.apache.log4j.Appender क्लास के लिए "setThreshold" विधि प्रतीत नहीं होती है। मैंने "सेट थ्रेसहोल्ड" लाइन पर टिप्पणी की, लेकिन अभी भी कोई पासा नहीं - ब्राउज़र पर कुछ भी नहीं लिखा गया है। दिलचस्प बात यह है कि लॉग आउटपुट मेरे जेबॉस 7.1.1 सर्वर लॉग पर लिखा गया है। – Dave

0

इस तरह का एक सटीक उत्तर नहीं है, लेकिन मैंने इसे संभाला एक बेहतर तरीका है अपने स्वयं के एपेंडर को लिखना जो ThreadLocal में लॉग एकत्र करेगा। उस समय जब आपका सर्वलेट अनुरोध पूरा हो जाता है, तो आप ThreadLocal की सामग्री को निकाल सकते हैं और प्रतिक्रिया स्ट्रीम में उत्पादन कर सकते हैं, हालांकि आप चाहें।

यह धागा सुरक्षा के (अनकहा) आवश्यकता को संतुष्ट करता है, और काफी सफाई से log4j (या अन्य प्रवेश ढांचा) कार्यान्वयन कोड अलग कर सकते हैं (जो छोटा होना चाहिए, इस तकनीक का प्रयोग करके) जिसमें सका ThreadLocal के हेरफेर से, सिद्धांत को आपके कोड के अन्य क्षेत्रों में पुन: उपयोग किया जाए।

इस प्रकार की तकनीक का उपयोग कई सर्वर-साइड स्क्रिप्टिंग भाषाओं जैसे कोल्डफ्यूजन और अन्य द्वारा किया जाता है।

मैं संभावित कीड़े आप सकता है एक अनुप्रयोग सर्वर में ThreadLocal के अनुचित उपयोग के साथ कारण पर नहीं जाऊंगा, वहाँ इतना और अन्य साइटों पर इस का प्रबंधन करने, relevant answers के साथ साथ तकनीक है।

आशा है कि यह उत्तर आपकी सोच को थोड़ा अलग दिशा में रीडायरेक्ट कर सकता है!

संबंधित मुद्दे