2011-10-13 17 views
13

का उपयोग करके लॉग संदेश संशोधित करें सुरक्षा कारणों से, मुझे अपने ऐप में प्रत्येक लॉग संदेश को देखने की आवश्यकता है और लॉग फ़ाइल में जाने से पहले इसे संभवतः संशोधित करना होगा। मैंने सोचा कि मैं एक कस्टम एपेंडर (DailyRollingFileAppender का विस्तार) लिख सकता हूं और subAppend (LoggingEvent ईवेंट) को ओवरराइड कर सकता हूं। समस्या यह है कि LoggingEvent में संदेश पाठ के लिए कोई सेटटर नहीं है, और संदेश एक निजी विशेषता है। मैं अपने संशोधित संदेश के साथ एक नया लॉगिंगवेंट बना सकता हूं, लेकिन एपीआई शेष मूल लॉगिंगएवेंट पर प्रतिलिपि बनाना आसान नहीं बनाता है। यह सब एक कस्टम एपेंडर में संदेश के साथ दखल देने के लिए डिज़ाइन किया गया है।LOG4J: कस्टम एपेंडर

एकमात्र अन्य विकल्प जिसे मैं देख सकता हूं, एक नई वैश्विक विधि को कॉल करने के लिए सैकड़ों लॉगिंग स्टेटमेंट को संशोधित करना है जो पहले टेक्स्ट को संशोधित कर सकता है और फिर लॉग 4 जे कॉल कर सकता है। मै शायद नहीं!

क्या किसी और को कस्टम एपेंडर में लॉग संदेश को संशोधित करने की आवश्यकता है?

उत्तर

0

मैं Logger के लिए एक प्रतिनिधि वर्ग बनाने के लिए जाऊंगा और org.apache.log4j.Logger से your.own.Logger पर सभी आयातों को बदल दूंगा। यह एक सरल और स्वचालित प्रक्रिया — है क्योंकि आप कोड में लॉगर कॉल बदलने पर विचार करते हैं, मुझे लगता है कि आपके पास स्रोत कोड तक पूर्ण पहुंच है। प्रतिनिधि में आप log4j लॉगर से बिल्कुल विधियों को कॉल करेंगे, लेकिन स्ट्रिंग्स के साथ पहले अपने दिल की सामग्री में दखल दें।

मैंने कोड के माध्यम से ब्राउज़ किया है और संस्करण 1.2.15 से पहले एक नया LoggingEvent बनाकर लाइब्रेरी के आधे से खोले बिना असंभव है। 1.2.15 से इसमें कोई समस्या नहीं है।

11

मुझे पूरा यकीन नहीं है कि नया LoggingEvent क्यों बनाना इतना कठिन है।

package test.logging; 

import org.apache.log4j.DailyRollingFileAppender; 
import org.apache.log4j.spi.LoggingEvent; 

public class MyDailyRollingFileAppender extends DailyRollingFileAppender { 

    @Override 
    protected void subAppend(LoggingEvent event) { 
     String modifiedMessage = String.format("**** Message modified by MyDailyRollingFileAppender ****\n\n%s\n\n**** Finished modified message ****", event.getMessage()); 
     LoggingEvent modifiedEvent = new LoggingEvent(event.getFQNOfLoggerClass(), event.getLogger(), event.getTimeStamp(), event.getLevel(), modifiedMessage, 
                 event.getThreadName(), event.getThrowableInformation(), event.getNDC(), event.getLocationInformation(), 
                 event.getProperties()); 

     super.subAppend(modifiedEvent); 
    } 

} 

इस परीक्षण के साथ:

package test; 

import org.apache.log4j.Logger; 

public class TestLogging { 

    public static void main(String[] args) { 
     Logger log = Logger.getLogger(TestLogging.class); 
     log.info("I am testing my logging"); 
     log.info("Here is an exception", new Exception()); 
    } 

} 

और इस विन्यास:

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> 

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> 

    <appender name="MyDailyRollingFileAppender" class="test.logging.MyDailyRollingFileAppender"> 
     <param name="Append" value="true"/> 
     <param name="datePattern" value="'.'yyyy-MM-dd"/> 
     <param name="File" value="mine.log"/> 
     <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%d %-5p (%x) [%t] %c{1} - %m%n" /> 
     </layout> 
    </appender> 

    <root> 
     <priority value="debug"/> 
     <appender-ref ref="MyDailyRollingFileAppender"/> 
    </root> 

</log4j:configuration> 

मैं निम्नलिखित उत्पादन हो रही है:

2011-10-14 10:09:09,322 INFO () [main] TestLogging - **** Message modified by MyDailyRollingFileAppender **** 

I am testing my logging 

**** Finished modified message **** 
2011-10-14 10:09:09,333 INFO () [main] TestLogging - **** Message modified by MyDailyRollingFileAppender **** 

Here is an exception 

**** Finished modified message **** 
java.lang.Exception 
    at test.TestLogging.main(TestLogging.java:10) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) 

यह मेरे लिए काम करने लगता है हालांकि मैंने कुछ सिमुला किया है इसके लिए, मैंने थोड़ा अलग दृष्टिकोण इस्तेमाल किया। प्रत्येक प्रकार के Appender के सबक्लास लिखने के बजाय मैं उपयोग करना चाहता था, मैंने Appender बनाया जो अन्य Appender ऑब्जेक्ट्स को लपेटता है, और लिपटे Appender एस को भेजने से पहले संदेश को संशोधित करता है। कुछ इस तरह:

package test.logging; 

import org.apache.log4j.Appender; 
import org.apache.log4j.AppenderSkeleton; 
import org.apache.log4j.spi.AppenderAttachable; 
import org.apache.log4j.spi.LoggingEvent; 

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Enumeration; 
import java.util.Iterator; 
import java.util.List; 

public class MyAppenderWrapper extends AppenderSkeleton implements AppenderAttachable { 

    private final List<Appender> appenders = new ArrayList<Appender>(); 

    public void close() { 
     synchronized (appenders) { 
      for (Appender appender : appenders) { 
       appender.close(); 
      } 
     } 
    } 

    public boolean requiresLayout() { 
     return false; 
    } 

    public void addAppender(Appender appender) { 
     synchronized (appenders) { 
      appenders.add(appender); 
     } 
    } 

    public Enumeration getAllAppenders() { 
     return Collections.enumeration(appenders); 
    } 

    public Appender getAppender(String name) { 
     synchronized (appenders) { 
      for (Appender appender : appenders) { 
       if (appender.getName().equals(name)) { 
        return appender; 
       } 
      } 
     } 
     return null; 
    } 

    public boolean isAttached(Appender appender) { 
     synchronized (appenders) { 
      for (Appender wrapped : appenders) { 
       if (wrapped.equals(appender)) { 
        return true; 
       } 
      } 
      return false; 
     } 
    } 

    public void removeAllAppenders() { 
     synchronized (appenders) { 
      appenders.clear(); 
     } 
    } 

    public void removeAppender(Appender appender) { 
     synchronized (appenders) { 
      for (Iterator<Appender> i = appenders.iterator(); i.hasNext();) { 
       if (i.next().equals(appender)) { 
        i.remove(); 
       } 
      } 
     } 
    } 

    public void removeAppender(String name) { 
     synchronized (appenders) { 
      for (Iterator<Appender> i = appenders.iterator(); i.hasNext();) { 
       if (i.next().getName().equals(name)) { 
        i.remove(); 
       } 
      } 
     } 
    } 

    @Override 
    protected void append(LoggingEvent event) { 
     String modifiedMessage = String.format("**** Message modified by MyAppenderWrapper ****\n\n%s\n\n**** Finished modified message ****", event.getMessage()); 
     LoggingEvent modifiedEvent = new LoggingEvent(event.getFQNOfLoggerClass(), event.getLogger(), event.getTimeStamp(), event.getLevel(), modifiedMessage, 
                 event.getThreadName(), event.getThrowableInformation(), event.getNDC(), event.getLocationInformation(), 
                 event.getProperties()); 

     synchronized (appenders) { 
      for (Appender appender : appenders) { 
       appender.doAppend(modifiedEvent); 
      } 
     } 
    } 

} 

जो तुम जैसे कॉन्फ़िगर कर सकते हैं:

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> 

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> 

    <appender name="StdOut" class="org.apache.log4j.ConsoleAppender"> 
     <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%d %-5p (%x) [%t] %c{1} - %m%n" /> 
     </layout> 
    </appender> 

    <appender name="FileAppender" class="org.apache.log4j.DailyRollingFileAppender"> 
     <param name="Append" value="true"/> 
     <param name="datePattern" value="'.'yyyy-MM-dd"/> 
     <param name="File" value="mine.log"/> 
     <layout class="org.apache.log4j.PatternLayout"> 
      <param name="ConversionPattern" value="%d %-5p (%x) [%t] %c{1} - %m%n" /> 
     </layout> 
    </appender> 

    <appender name="AppenderWrapper" class="test.logging.MyAppenderWrapper"> 
     <appender-ref ref="StdOut"/> 
     <appender-ref ref="FileAppender"/> 
    </appender> 

    <root> 
     <priority value="debug"/> 
     <appender-ref ref="AppenderWrapper"/> 
    </root> 

</log4j:configuration> 

इस तरह संदेश अभी भी मूल appenders के लिए, लेकिन संशोधित संदेश भेजा है।

+2

यह काम करता है क्योंकि आप संस्करण 1.2.15+ का उपयोग कर रहे हैं। पिछले log4j संस्करणों में आपके उदाहरणों में उपयोग की जाने वाली कुछ विधियां नहीं थीं, इसलिए लेखक की समस्या। कई परियोजनाएं संस्करण 1.2.14 का उपयोग करती हैं, क्योंकि यह लंबे समय तक नवीनतम थी। – MaDa

+1

मैंने 1.2.16 तक अपग्रेड किया और एक नया लॉगिंगईवेंट बनाने के लिए आपके उदाहरण का उपयोग करने में सक्षम था। सहायता के लिए धन्यवाद! – user993719

4

एक और विकल्प आपके एपेंडर द्वारा उपयोग किए गए लेआउट को कस्टमाइज़ करना है। चूंकि लेआउट एक स्ट्रिंग में लॉग इवेंट को क्रमबद्ध करने के लिए ज़िम्मेदार है, इसलिए मैं जांचता हूं कि क्या लेआउट को जोड़ना ऐपेंडर और घटनाओं को बदलने से कम जटिल है। एक विचार है...

+0

हां! परिशिष्ट संशोधित करने के बजाए यह एक विशिष्ट दृष्टिकोण की तरह लगता है। कई परिशिष्टों के स्थान पर एक कस्टम लेआउट का भी उपयोग किया जा सकता है – hellojava

3

Thats मैं कैसे किया के बाद से मैं appender अनुकूलित करने का log4j के एक पुराने संस्करण के साथ काम कर रहा हूँ

इसके बजाय, मैं लेआउट अनुकूलित और कहा कि लेआउट जो भी appender में मैं इस सुविधा की जरूरत के लिए भेजा

public class LogValidatorLayout extends PatternLayout { 

    public LogValidatorLayout() { 
     super(); 
    } 

    public LogValidatorLayout(String pattern) { 
     super(pattern); 
    } 

    @Override 
    public String format(LoggingEvent event) { 

     // only process String type messages 
     if (event.getMessage() != null && event.getMessage() instanceof String) { 

      String message = event.getMessage().toString(); 
      message = StringUtils.trim("Some custom text --->>"+message); 

      // earlier versions of log4j don't provide any way to update messages, 
      // so use reflections to do this 
      try { 
       Field field = LoggingEvent.class.getDeclaredField("message"); 
       field.setAccessible(true); 
       field.set(event, message); 
      } catch (Exception e) { 
       // Dont log it as it will lead to infinite loop. Simply print the trace 
       e.printStackTrace(); 
      } 

     } 

     return super.format(event); 
    } 

} 

और अपने log4j.properties या xml में, इस लेआउट को पंजीकृत करें

log4j.appender.STDOUT.layout=a.b.c.package.LogValidatorLayout