2011-10-02 12 views
18

मैं वर्तमान में जावा में एक बड़ी परियोजना लिख ​​रहा हूं, कई वर्गों के साथ, कुछ वर्ग शांत हैं, जो केवल कुछ विधियों के साथ वस्तुओं का प्रतिनिधित्व करते हैं। मेरे पास मेरी मुख्य कक्षा में लॉगर सेट है, और यह ठीक काम करता है। मैं सभी वर्गों के साथ केवल एक लॉगर (एक कंसोल एपेंडर के साथ) का उपयोग करने में सक्षम होना चाहता हूं। मैंने विभिन्न वर्गों में लॉगर के संदर्भ को पारित करने का प्रयास किया, लेकिन यह सही नहीं दिख रहा है। इसके अलावा, कभी-कभी मैं मुख्य भाग के बिना कक्षाओं पर परीक्षण चला रहा हूं, और इस प्रकार लॉगर अन्य वर्गों के लिए प्रारंभ नहीं किया गया है।एकाधिक कक्षाओं के साथ log4j का उपयोग कैसे करें?

इसे पूरा करने के लिए सबसे अच्छा तरीका क्या है, मेरा मतलब है, विभिन्न वर्गों से एक लॉग में लॉग इन करने के लिए, कक्षाओं के बीच कोई कठोर निर्भरता नहीं है और प्रत्येक वर्ग के साथ स्वतंत्र रूप से लॉग का उपयोग करने की क्षमता के साथ?

उत्तर

16

अगर मैं सही ढंग से समझ, आप क्या क्षण में है:

public class Main { 
    public static final Logger LOGGER = Logger.getLogger(Main.class); 
} 

public class AnotherClass { 
    public void doSomething() { 
     Main.LOGGER.debug("value=" + value); 
    } 
} 

या, आप वर्ग के निर्माताओं में एक लकड़हारा के लिए संदर्भ गुजरती हैं।

public class Main { 
    private static final Logger LOGGER = Logger.getLogger("GLOBAL"); 
} 

public class AnotherClass { 
    private final Logger LOGGER = Logger.getLogger("GLOBAL"); 

    public void doSomething() { 
     LOGGER.debug("value=" + value); 
    } 
} 

यह बिल्कुल वैसा ही लकड़हारा का उपयोग करता है, Logger.getLogger दोनों कॉल में एक ही वस्तु रिटर्न:

सबसे पहले, आप बस एक ही मूल्य, Logger.getLogger के लिए पारित की तरह का उपयोग करके एक वैश्विक लकड़हारा उपयोग कर सकते हैं । अब कक्षाओं के बीच निर्भरता नहीं है, और यह काम करेगा।

दूसरी बात जो मैं आपकी टिप्पणियों से इकट्ठा करता हूं वह यह है कि आप हाथ से कॉन्फ़िगर कर रहे हैं (BasicConfigurator.configure का उपयोग करके। अधिकांश समय यह आवश्यक नहीं है, और आपको केवल log4j.properties या log4j जोड़कर अपनी कॉन्फ़िगरेशन करनी चाहिए। xml आपके क्लासपाथ में। ग्रहण में यह इसे src/(या src/main/संसाधनों में जोड़कर किया जाता है यदि आप मेवेन का उपयोग कर रहे हैं)। यदि आप जूनिट का उपयोग कर रहे हैं, तो इसे परीक्षण/स्रोत निर्देशिका में जोड़ें (या src/मेवेन के साथ परीक्षण/संसाधन)। यह लॉग 4j को कॉन्फ़िगर करने का एक बेहतर दीर्घकालिक तरीका है, क्योंकि आपको कक्षाओं के बीच जानकारी पास करने की आवश्यकता नहीं है।

इसके अलावा, लॉगर्स का उपयोग करने का अनुशंसित तरीका कक्षा को Logger.getLogger() में पास करना है। इस तरह आप अपने उत्पादन वर्ग के नाम पर आधारित है, जो आम तौर पर बहुत अधिक उपयोगी सिर्फ एक वैश्विक लकड़हारा की तुलना में है फ़िल्टर कर सकते हैं:

public class Main { 
    private static final Logger LOGGER = Logger.getLogger(Main.class); 
    public static final main(String[] args) { 
     LOGGER.debug("started"); 
    } 
} 

public class AnotherClass { 
    private final Logger LOGGER = Logger.getLogger(this.getClass()); 

    public void doSomething() { 
     LOGGER.debug("value=" + value); 
    } 
} 
फिर log4j.properties में

, आप एक फाइल करने के लिए एक एकल appender कॉन्फ़िगर कर सकते हैं ।

# Set root logger level to DEBUG and its only appender to A1. 
log4j.rootLogger=DEBUG, A1 

# A1 is set to be a ConsoleAppender. 
log4j.appender.A1=org.apache.log4j.ConsoleAppender 

# A1 uses PatternLayout. 
log4j.appender.A1.layout=org.apache.log4j.PatternLayout 
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n 

अंत में, आपके सभी लॉगर्स को स्थिर के रूप में घोषित करना आवश्यक नहीं है। यदि आप ऑब्जेक्ट सृजन के लॉट [*] कर रहे हैं तो यह केवल एक उल्लेखनीय अंतर बनाता है। गैर-स्थैतिक फ़ील्ड के रूप में अपने लॉगर्स को घोषित करने से आप Logger.getLogger(this.getClass()); का उपयोग कर सकते हैं, जिस स्थिति में कक्षा में लॉगर जोड़ना एक पंक्ति का कट और पेस्ट बन जाता है। Should I declare Log references static or not? देखें (दुर्भाग्य से विकी पेज का लिंक टूटा हुआ है), लेकिन slf4j page में भी एक अच्छी व्याख्या है। तो गैर स्थैतिक फ़ील्ड का उपयोग करें जब तक कि आपके पास बहुत अच्छा कारण न हो।

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

[*] और मेरा मतलब बहुत है।

+0

मैंने ठीक उसी तरह किया जैसा आपने उल्लेख किया है, लेकिन मुख्य वर्ग में केवल लॉग मुद्रित हो जाते हैं, अन्य तरीकों से लॉग मुद्रित नहीं होते हैं? इसे कैसे जोड़ेंगे –

5

Your logger instances should typically be private, static and final। ऐसा करके, प्रत्येक वर्ग में इसका स्वयं का लॉगर इंस्टेंस होगा (जिसे वर्ग लोड होने के बाद बनाया जाता है), ताकि आप उस वर्ग की पहचान कर सकें जहां लॉग रिकॉर्ड बनाया गया था, और आपको कक्षाओं में लॉगर इंस्टेंस पास करने की आवश्यकता नहीं है।

+0

मैं "BasicConfigurator.configure();" कहां डालूं? एक मुख्य विधि के बिना कक्षा में? – stdcall

+0

@Mellowcandle, आपको प्रत्येक वर्ग में 'BasicConfigurator.configure()' को आमंत्रित करने की आवश्यकता नहीं है। ऐसा करें, केवल कक्षा के आपके मुख्य तरीके में जो आपके ऐप को आरंभ करता है, और केवल तभी आपको करना होगा। संपादित करें: ['BasicConfigurator.configure'] (http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/BasicConfigurator.html#configure%28%29) लॉग 4j सेटअप बनाने के लिए उपयोग किया जाता है, जब आपके पास परिशिष्ट और लेआउट के साथ कॉन्फ़िगर की गई एक कार्यात्मक log4j.properties फ़ाइल की कमी होती है। –

+0

आपका क्या मतलब है? मुझे कई वर्गों पर यूनिट-टेस्ट चलाने की जरूरत है। मुझे इसे कब चलाना है? – stdcall

4

ऐसा करने का सबसे अच्छा तरीका यह है कि प्रत्येक वर्ग में इसका अपना लॉगर (वर्ग के नाम पर) होता है, फिर अपनी कॉन्फ़िगरेशन सेट करें ताकि वे सभी एक ही एपेंडर में शामिल हो जाएं।

उदाहरण के लिए:

# Set root logger level to DEBUG and its only appender to A1. 
log4j.rootLogger=DEBUG, A1 

# A1 is set to be a ConsoleAppender. 
log4j.appender.A1=org.apache.log4j.ConsoleAppender 

# A1 uses PatternLayout. 
log4j.appender.A1.layout=org.apache.log4j.PatternLayout 
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n 

दोनों A और B के लिए रूट लकड़हारा करने के लिए लॉग इन करें और इसलिए होगा:

class A { 
    private static final Logger log = Logger.getLogger(A.class); 
} 

class B { 
    private static final Logger log = Logger.getLogger(B.class); 
} 

फिर अपने log4j.properties log4j दस्तावेज में उदाहरण की तरह लग सकता है एक ही एपेंडर (इस मामले में कंसोल)।

यह आपको वह देगा जो आप चाहते हैं: प्रत्येक वर्ग स्वतंत्र है लेकिन वे सभी एक ही लॉग पर लिखते हैं। आपको बोनस सुविधा भी मिलती है जिसे आप log4j कॉन्फ़िगरेशन में प्रत्येक वर्ग के लिए लॉगिंग स्तर बदल सकते हैं।

एक तरफ के रूप में, यदि आप अभी भी प्रारंभिक विकास में हैं तो आप slf4j पर जाने पर विचार करना चाहेंगे। slf4j में log4j पर कुछ संवर्द्धन हैं जो इसे काम करने में थोड़ा आसान बनाता है।

+0

मैं "BasicConfigurator.configure();" कहां रखूं? बिना किसी मुख्य विधि के कक्षा में? – stdcall

+2

@Mellowcandle: मत करो। 'Log4j.properties' फ़ाइल का प्रयोग करें।आपको इसे क्लासपाथ पर रखना होगा और log4j इसका उपयोग करेगा। –

+0

@ कैमरून स्किनर मैंने बिल्कुल उल्लेख किया है, लेकिन मुख्य वर्ग में लॉग केवल कंसोल में मुद्रित हो जाते हैं, अन्य तरीकों में लॉग मुद्रित नहीं होते हैं, इसे कैसे ठीक किया जाए? –

1

आपके पास एकाधिक लॉगर उदाहरण हैं क्योंकि आप लॉगिंग करते समय उन्हें अलग व्यवहार करना चाहते हैं (आमतौर पर उस क्लास नाम को प्रिंट करके, जिसे वे कॉन्फ़िगर करते हैं)। यदि आपको इसकी परवाह नहीं है, तो आप कक्षा में केवल एक स्थिर लॉगर उदाहरण बना सकते हैं और उस स्थान पर इसका उपयोग कर सकते हैं।

एकल लॉगर बनाने के लिए, आप केवल एक स्थिर उपयोगिता लॉगिंग क्लास को एकल बिंदु लॉगर होने के लिए बना सकते हैं, इसलिए यदि हमें लॉगर पैकेज को बदलने की आवश्यकता है, तो आप केवल इस कक्षा को अपडेट करेंगे।

final public class Logger { 
    private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger("Log"); 

    enum Level {Error, Warn, Fatal, Info, Debug} 

    private Logger() {/* do nothing */}; 

    public static void logError(Class clazz, String msg) { 
     log(Level.Error, clazz, msg, null); 
    } 

    public static void logWarn(Class clazz, String msg) { 
     log(Level.Warn, clazz, msg, null); 
    } 

    public static void logFatal(Class clazz, String msg) { 
     log(Level.Fatal, clazz, msg, null); 
    } 

    public static void logInfo(Class clazz, String msg) { 
     log(Level.Info, clazz, msg, null); 
    } 

    public static void logDebug(Class clazz, String msg) { 
     log(Level.Debug, clazz, msg, null); 
    } 


    public static void logError(Class clazz, String msg, Throwable throwable) { 
     log(Level.Error, clazz, msg, throwable); 
    } 


    public static void logWarn(Class clazz, String msg, Throwable throwable) { 
     log(Level.Warn, clazz, msg, throwable); 
    } 

    public static void logFatal(Class clazz, String msg, Throwable throwable) { 
     log(Level.Fatal, clazz, msg, throwable); 
    } 

    public static void logInfo(Class clazz, String msg, Throwable throwable) { 
     log(Level.Info, clazz, msg, throwable); 
    } 

    public static void logDebug(Class clazz, String msg, Throwable throwable) { 
     log(Level.Debug, clazz, msg, throwable); 
    } 

    private static void log(Level level, Class clazz, String msg, Throwable throwable) { 
     String message = String.format("[%s] : %s", clazz, msg); 
     switch (level) { 
      case Info: 
       logger.info(message, throwable); 
       break; 
      case Warn: 
       logger.warn(message, throwable); 
       break; 
      case Error: 
       logger.error(message, throwable); 
       break; 
      case Fatal: 
       logger.fatal(message, throwable); 
       break; 
      default: 
      case Debug: 
       logger.debug(message, throwable); 
     } 
    } 

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