2009-12-18 14 views
10

मैं एक परियोजना में काम करता हूं जो Log4J का उपयोग करता है। प्रत्येक थ्रेड के लिए एक अलग लॉग फ़ाइल बनाने की आवश्यकता है; यह स्वयं एक अजीब मुद्दा था, कुछ हद तक फ्लाई पर एक नया FileAppender बनाकर और लॉगर इंस्टेंस को अटैच करके सॉर्ट किया गया। जब तक हम महसूस किया कि एक और पुस्तकालय उपयोग हमLog4J - SiftingAppender की तरह कार्यक्षमता

Logger logger = Logger.getLogger(<thread dependent string>); 
FileAppender appender = new FileAppender(); 
appender.setFile(fileName); 
appender.setLayout(new PatternLayout(lp.getPattern())); 
appender.setName(<thread dependent string>); 
appender.setThreshold(Level.DEBUG); 
appender.activateOptions(); 
logger.addAppender(appender); 

सब कुछ ठीक चला गया - Spring Framework v3.0.0 (जो का उपयोग Commons Logging) - स्प्रिंग लॉगिंग डेटा "देखा" है केवल initialised Appenders द्वारा - ऊपर तकनीक के साथ गेंद खेलने नहीं करता है log4.configuration फ़ाइल से लेकिन रनटाइम द्वारा परिशिष्ट नहीं बनाया गया। तो, वर्ग एक पर वापस।

कुछ जांच के बाद, मुझे लगता है कि नया पता चला और बेहतर LogBack एक appender है - SiftingAppender - जो वास्तव में क्या हम स्वतंत्र फाइलों पर अर्थात धागा स्तर प्रवेश की आवश्यकता है।

फिलहाल, लॉगबैक पर जाना एक विकल्प नहीं है, इसलिए, लॉग 4 जे के साथ फंस गया है, मैं सिफ्टिंग ऐपेंडर जैसी कार्यक्षमता कैसे प्राप्त कर सकता हूं और वसंत को भी खुश रख सकता हूं?

नोट: वसंत का उपयोग केवल JdbcTemplate कार्यक्षमता के लिए किया जाता है, कोई आईओसी नहीं;

log4j.logger.org.springframework = डीबग

निर्देश दिए here रूप

: क्रम में "हुक" वसंत के कॉमन्स Log4J लिए लॉग इन करना मैं log4j.properties फ़ाइल में इस लाइन जोड़ा है।

+1

यदि आप केवल जेडीबीसी कार्यक्षमता के लिए वसंत का उपयोग कर रहे हैं, तो आप इसके बजाय apache commons-dbutils जैसे कुछ का उपयोग करने पर विचार करना चाहेंगे। –

उत्तर

3

लॉगबैक slf4j api के माध्यम से पहुंचा जा सकता है। एक एडाप्टर लाइब्रेरी है जिसे jcl-over-sjf4j कहा जाता है जो कॉमन्स लॉगिंग इंटरफेस का खुलासा करता है लेकिन slf4j एपीआई पर सभी लॉगिंग करता है, जो सीधे कार्यान्वयन - लॉगबैक पर जाता है। आप Maven का उपयोग कर रहे हैं, तो यहाँ निर्भरता हैं:

<dependency> 
    <groupId>org.slf4j</groupId> 
    <artifactId>slf4j-api</artifactId> 
    <version>1.5.8</version> 
</dependency> 
<dependency> 
    <groupId>org.slf4j</groupId> 
    <artifactId>jcl-over-slf4j</artifactId> 
    <version>1.5.8</version> 
</dependency> 
<dependency> 
    <groupId>ch.qos.logback</groupId> 
    <artifactId>logback-core</artifactId> 
    <version>0.9.18</version> 
</dependency> 

(और अपवर्जन सूची में कॉमन्स-लॉगिंग जोड़ने के लिए, here देखें)

0

मैं slf4j अग्रभाग/पुनः रूटर के सभी शामिल करना चाहते/whateveryoucallthem। "प्रदान" हैक भी ध्यान दें, जो निर्भरता को कॉमन्स लॉगिंग में खींचने से रोकता है; पहले मैं संस्करण-99.0-अस्तित्व में मौजूद एक नकली खाली कॉमन्स लॉगिंग लाइब्रेरी का उपयोग कर रहा था।

इसके अलावा http://blog.springsource.com/2009/12/04/logging-dependencies-in-spring/

<dependencies> 
    <dependency> 
     <groupId>commons-logging</groupId> 
     <artifactId>commons-logging</artifactId> 

     <!-- use provided scope on real JCL instead --> 
     <!-- <version>99.0-does-not-exist</version> --> 

     <version>1.1.1</version> 

     <scope>provided</scope> 
    </dependency> 

    <dependency> 
     <groupId>commons-logging</groupId> 
     <artifactId>commons-logging-api</artifactId> 

     <!-- use provided scope on real JCL instead --> 
     <!-- <version>99.0-does-not-exist</version> --> 

     <version>1.1</version> 

     <scope>provided</scope> 
    </dependency> 

    <!-- the slf4j commons-logging replacement --> 
    <!-- if any package is using jakarta commons logging this will --> 
    <!-- re-route it through slf4j. --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>jcl-over-slf4j</artifactId> 

     <version>${version.slf4j}</version> 
    </dependency> 

    <!-- the slf4j log4j replacement. --> 
    <!-- if any package is using log4j this will re-route --> 
    <!-- it through slf4j. --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>log4j-over-slf4j</artifactId> 

     <version>${version.slf4j}</version> 
    </dependency> 

    <!-- the slf4j java.util.logging replacement. --> 
    <!-- if any package is using java.util.logging this will re-route --> 
    <!-- it through slf4j. --> 
    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>jul-to-slf4j</artifactId> 
     <version>${version.slf4j}</version> 
    </dependency> 

    <dependency> 
     <groupId>org.slf4j</groupId> 
     <artifactId>slf4j-api</artifactId> 

     <version>${version.slf4j}</version> 
    </dependency> 

    <dependency> 
     <groupId>ch.qos.logback</groupId> 
     <artifactId>logback-classic</artifactId> 

     <version>${version.logback}</version> 
    </dependency> 
</dependencies> 

<properties> 
    <version.logback>0.9.15</version.logback> 
    <version.slf4j>1.5.8</version.slf4j> 
</properties> 
0

देखते हैं कि आप log4j.NDC और MDC पर ध्यान दिया है? यह आपको कम से कम थ्रेड विशिष्ट डेटा को आपके लॉगिंग में टैग करने की अनुमति देता है। बिल्कुल नहीं जो आप पूछ रहे हैं, लेकिन उपयोगी हो सकता है। एक चर्चा here है।

3

मैं लॉग 4j में SiftingAppender की तरह कार्यक्षमता खोजने के लिए थोड़ी देर के लिए संघर्ष कर रहा था (हम कुछ निर्भरताओं के कारण लॉगबैक पर स्विच नहीं कर सका), और एक प्रोग्रामेटिक समाधान के साथ समाप्त हुआ जो एमडीसी का उपयोग करके और लॉगर्स को जोड़कर बहुत अच्छी तरह से काम करता है क्रम:

// this can be any thread-specific string 
String processID = request.getProcessID(); 

Logger logger = Logger.getRootLogger(); 

// append a new file logger if no logger exists for this tag 
if(logger.getAppender(processID) == null){ 

    try{ 
    String pattern = "%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n"; 
    String logfile = "log/"+processID+".log"; 

    FileAppender fileAppender = new FileAppender(
     new PatternLayout(pattern), logfile, true); 
    fileAppender.setName(processID); 

    // add a filter so we can ignore any logs from other threads 
    fileAppender.addFilter(new ProcessIDFilter(processID)); 

    logger.addAppender(fileAppender); 
    }catch(Exception e){ 
    throw new RuntimeException(e); 
    } 
} 

// tag all child threads with this process-id so we can separate out log output 
MDC.put("process-id", processID); 

//whatever you want to do in the thread 
LOG.info("This message will only end up in "+processID+".log!"); 

MDC.remove("process-id"); 

फिल्टर बस ऊपर संलग्न एक विशिष्ट प्रक्रिया आईडी की जांच करता है:

public class RunIdFilter extends Filter { 

    private final String runId; 

    public RunIdFilter(String runId) { 
    this.runId = runId; 
    } 

    @Override 
    public int decide(LoggingEvent event) { 
    Object mdc = event.getMDC("run-id"); 

    if (runId.equals(mdc)) { 
     return Filter.ACCEPT; 
    } 

    return Filter.DENY; 
    } 
} 

आशा है कि यह एक बिट में मदद करता है।

0

Log4j2 में, हम अब RoutingAppender उपयोग कर सकते हैं:

RoutingAppender एक अधीनस्थ appender को LogEvents और फिर उन्हें मार्गों मूल्यांकन करता है। लक्षित एपेंडर पहले से कॉन्फ़िगर किया गया एक एपेंडर हो सकता है और इसके नाम से संदर्भित किया जा सकता है या एपेंडर को गतिशील रूप से आवश्यकतानुसार बनाया जा सकता है।

उनके FAQ से:

मैं गतिशील रूप से लॉग फ़ाइलें अलग करने के लिए लिख सकता हूँ? रूटिंग एपेंडर को देखें। आप कॉन्फ़िगरेशन में एकाधिक मार्गों को परिभाषित कर सकते हैं, और थ्रेडकॉन्टेक्स्ट मानचित्र में मान डाल सकते हैं जो यह निर्धारित करता है कि इस थ्रेड में कौन सी लॉग फ़ाइल बाद की घटनाएं लॉग ऑन हो जाती हैं।

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