जावा में डिबग आउटपुट को संभालने का सही तरीका क्या है?


32

जैसा कि मेरे वर्तमान जावा प्रोजेक्ट बड़े और बड़े होते हैं, मुझे लगता है कि इसी तरह से मेरे कोड के कई बिंदुओं में डिबग आउटपुट डालने की आवश्यकता बढ़ रही है।

इस सुविधा को उचित रूप से सक्षम या अक्षम करने के लिए, परीक्षण सत्रों को खोलने या बंद करने के आधार पर, मैं आमतौर private static final boolean DEBUG = falseपर उन कक्षाओं की शुरुआत में रखता हूं जिनका मेरे परीक्षण निरीक्षण कर रहे हैं, और तुच्छ रूप से इसका उपयोग इस तरह से करते हैं (उदाहरण के लिए):

public MyClass {
  private static final boolean DEBUG = false;

  ... some code ...

  public void myMethod(String s) {
    if (DEBUG) {
      System.out.println(s);
    }
  }
}

और जैसे।

लेकिन यह मुझे आनंद नहीं देता है, क्योंकि निश्चित रूप से यह काम करता है, लेकिन ऐसे कई वर्ग हो सकते हैं जिनमें DEBUG को सही पर सेट करना है, यदि आप उनमें से सिर्फ एक जोड़े को नहीं देख रहे हैं।

इसके विपरीत, मैं (जैसे - मुझे लगता है - कई अन्य) पूरे आवेदन को डिबग मोड में रखना पसंद नहीं करेंगे, क्योंकि पाठ की मात्रा आउटपुट हो सकती है।

तो, क्या ऐसी स्थिति को वास्तुशिल्प रूप से संभालने का एक सही तरीका है या सबसे सही तरीका DEBUG वर्ग के सदस्य का उपयोग करना है?


14
जावा में, लॉगिंग के लिए homebrew कोड का उपयोग करने का सही तरीका नहीं है। एक स्थापित ढांचा चुनें, पहिया को फिर से
मजबूत

मैं अपने कुछ और अधिक जटिल वर्गों में बूलियन DEBUG का उपयोग करता हूं, जैसा कि आपने कहा था। मैं आमतौर पर पूरे आवेदन को डिबग नहीं करना चाहता, बस मुझे समस्याएं दे रहा है। यह आदत मेरे COBOL दिनों से चली आ रही है, जहाँ DISPLAY कथन केवल डीबगिंग का एकमात्र रूप उपलब्ध थे।
गिल्बर्ट ले ब्लैंक

1
मैं एक डिबगर पर अधिक भरोसा करने की भी सिफारिश करूंगा जब संभव हो और डिबग स्टेटमेंट के साथ अपने कोड को लैटरिंग न करें।
एंड्रयू टी फिनेल

1
क्या आप इकाई परीक्षण के साथ टेस्ट ड्रिवेन डेवलपमेंट (TDD) का अभ्यास करते हैं? एक बार जब मैंने ऐसा करना शुरू किया, तो मैंने 'डिबग कोड' में भारी कमी देखी।
JW01

जवाबों:


52

आप लॉगिंग फ़्रेमवर्क को देखना चाहते हैं, और शायद लॉगिंग फ़ेसडे फ्रेमवर्क को।

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

फ़्रेमवर्क

कुछ लॉगिंग फ्रेमवर्क

  • जावा लॉगिंग फ्रेमवर्क (JDK का हिस्सा),
  • अपाचे Log4J (थोड़ा पुराना है, लेकिन अभी भी मजबूत और सक्रिय रूप से बनाए रखा जा रहा है),
  • LogBack (, Log4J तुलना में एक अधिक आधुनिक दृष्टिकोण प्रदान करने के लिए के रचनाकारों में से एक के द्वारा बनाई गई Log4J )।

कुछ लॉगिंग facades

प्रयोग

मूल उदाहरण

इन चौखटों में से अधिकांश आपको कुछ प्रपत्र लिखने की अनुमति देते हैं (यहां उपयोग करके slf4j-apiऔर logback-core):

package chapters.introduction;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

// copied from: http://www.slf4j.org/manual.html
public class HelloWorld {

  public static void main(String[] args) {
    final Logger logger = LoggerFactory.getLogger(HelloWorld.class);

    logger.debug("Hello world, I'm a DEBUG level message");
    logger.info("Hello world, I'm an INFO level message");
    logger.warn("Hello world, I'm a WARNING level message");
    logger.error("Hello world, I'm an ERROR level message");
  }
}

एक समर्पित लकड़हारा बनाने के लिए वर्तमान वर्ग के उपयोग पर ध्यान दें, जो SLF4J / LogBack को आउटपुट स्वरूपित करने की अनुमति देगा और संकेत करेगा कि लॉगिंग संदेश कहां से आया है।

जैसा कि SLF4J मैनुअल में उल्लेख किया गया है , एक कक्षा में एक विशिष्ट उपयोग पैटर्न आमतौर पर है:

import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  

public class MyClass {

    final Logger logger = LoggerFactory.getLogger(MyCLASS.class);

    public void doSomething() {
        // some code here
        logger.debug("this is useful");

        if (isSomeConditionTrue()) {
            logger.info("I entered by conditional block!");
        }
    }
}

लेकिन वास्तव में, लकड़हारे को फॉर्म के साथ घोषित करना और भी सामान्य है:

private static final Logger LOGGER = LoggerFactory.getLogger(MyClass.class);

यह लॉगर को स्थिर तरीकों के भीतर से भी उपयोग करने की अनुमति देता है, और इसे कक्षा के सभी उदाहरणों के बीच साझा किया जाता है। यह आपके पसंदीदा रूप होने की काफी संभावना है। हालाँकि, जैसा कि टिप्पणियों में ब्रेंडन लांग ने कहा है, आप निहितार्थों को समझना और उसके अनुसार निर्णय लेना चाहते हैं (यह इन मुहावरों के बाद सभी लॉगिंग रूपरेखाओं पर लागू होता है)।

उदाहरण के लिए, एक नामांकित लकड़हारा बनाने के लिए स्ट्रिंग पैरामीटर का उपयोग करके, उदाहरण के लिए, लकड़हारे के अन्य तरीके हैं:

Logger logger = LoggerFactory.getLogger("MyModuleName");

डिबग स्तर

डिबग का स्तर एक फ्रेमवर्क से दूसरे फ्रेम में भिन्न होता है, लेकिन आम लोग हैं (आलोचनात्मकता के क्रम में, सौम्य से लेकर बैट-शिट खराब तक, और शायद बहुत आम से लेकर उम्मीद बहुत दुर्लभ तक):

  • TRACE बहुत विस्तृत जानकारी। केवल लॉग में लिखा जाना चाहिए। केवल चौकियों पर कार्यक्रम के प्रवाह को ट्रैक करने के लिए उपयोग किया जाता है।

  • DEBUG विस्तृत जानकारी। केवल लॉग में लिखा जाना चाहिए।

  • INFO उल्लेखनीय रनटाइम इवेंट। तुरंत एक कंसोल पर दिखाई देना चाहिए, इसलिए संयम से उपयोग करें।

  • WARNING रनटाइम विषमताएं और पुनर्प्राप्त करने योग्य त्रुटियां।

  • ERROR अन्य रनटाइम त्रुटियाँ या अप्रत्याशित स्थितियाँ।

  • FATAL समयपूर्व समाप्ति के कारण गंभीर त्रुटियां।

ब्लॉक और गार्ड

अब, मान लें कि आपके पास एक कोड सेक्शन है जहां आप कई डिबग स्टेटमेंट लिखने वाले हैं। यह आपके प्रदर्शन को जल्दी से प्रभावित कर सकता है, क्योंकि लॉगिंग के प्रभाव के कारण और किसी भी पैरामीटर की पीढ़ी जो आप लॉगिंग विधि से गुजर रहे हैं।

इस तरह के मुद्दे से बचने के लिए, आपका अक्सर फॉर्म का कुछ लिखना चाहता है:

if (LOGGER.isDebugEnabled()) {
   // lots of debug logging here, or even code that
   // is only used in a debugging context.
   LOGGER.debug(" result: " + heavyComputation());
}

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

विन्यास

कॉन्फ़िगरेशन आपके लॉगिंग ढांचे पर काफी निर्भर है, लेकिन वे इसके लिए ज्यादातर एक ही तकनीक प्रदान करते हैं:

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

वे ज्यादातर समान क्षमताओं की पेशकश भी करते हैं:

  • आउटपुट संदेश के प्रारूप का कॉन्फ़िगरेशन (टाइमस्टैम्प, मार्कर आदि ...),
  • उत्पादन स्तरों का विन्यास,
  • ठीक-दाने वाले फ़िल्टर का विन्यास (उदाहरण के लिए / पैकेज या कक्षाओं को शामिल / बाहर करना),
  • ऐप्पलेंडर्स का कॉन्फ़िगरेशन यह निर्धारित करने के लिए कि कहां लॉग इन करें (कंसोल करने के लिए, फाइल करने के लिए, एक वेब-सेवा के लिए ...) और संभवतः पुराने लॉग्स (उदाहरण के लिए, ऑटो रोलिंग फ़ाइलों के साथ) क्या करें।

logback.xmlफ़ाइल का उपयोग करते हुए यहां एक घोषणात्मक कॉन्फ़िगरेशन का एक सामान्य उदाहरण है ।

<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

जैसा कि उल्लेख किया गया है, यह आपके ढांचे पर निर्भर करता है और अन्य विकल्प भी हो सकते हैं (उदाहरण के लिए, लॉगबैक भी ग्रूवी स्क्रिप्ट का उपयोग करने की अनुमति देता है)। XML कॉन्फ़िगरेशन प्रारूप भी एक कार्यान्वयन से दूसरे में भिन्न हो सकता है।

अधिक कॉन्फ़िगरेशन उदाहरणों के लिए, कृपया (दूसरों के बीच) देखें:

कुछ ऐतिहासिक मज़ा

कृपया ध्यान दें कि फिलहाल Log4J एक बड़ा अपडेट देख रहा है, जो संस्करण 1.x से 2.x तक परिवर्तित हो रहा है । आप अधिक ऐतिहासिक मज़ा या भ्रम के लिए दोनों पर एक नज़र रखना चाहते हैं, और यदि आप Log4J को चुनते हैं तो संभवतः 2.20 संस्करण के साथ जाना पसंद करते हैं।

यह ध्यान देने योग्य है, जैसा कि माइक पार्टरिज ने टिप्पणियों में उल्लेख किया है, कि लॉगबैक को एक पूर्व लॉग 4 जे टीम के सदस्य द्वारा बनाया गया था। जिसे जावा लॉगिंग ढांचे की कमियों को दूर करने के लिए बनाया गया था। और यह कि आगामी प्रमुख Log4J 2.x संस्करण अब लॉगबैक से ली गई कुछ विशेषताओं को एकीकृत कर रहा है।

सिफ़ारिश करना

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

फिर भी, अगर मुझे आज एक संयोजन चुनना था, तो मैं LogBack + SLF4J के साथ जाऊंगा। लेकिन अगर आपने मुझसे कुछ साल बाद पूछा था कि मैं Apache Commons Logging के साथ Log4J की सिफारिश करूंगा, तो अपनी निर्भरता पर नज़र रखें और उनके साथ विकसित हों।


1
SLF4J और LogBack को उस लड़के ने लिखा था जिसने मूल रूप से Log4J लिखा था।
माइक पार्टरिज

4
उन लोगों के लिए जो लॉगिंग के प्रदर्शन प्रभावों के बारे में चिंतित हो सकते हैं: slf4j.org/faq.html#logging_performance
माइक

2
यह ध्यान देने योग्य है कि यह इतना स्पष्ट-कट नहीं है कि क्या आपको अपने लकड़हारे बनाने चाहिए static, क्योंकि यह थोड़ी मात्रा में मेमोरी बचाता है, लेकिन कुछ मामलों में समस्या पैदा करता है: slf4j.org/faq.html#declared_static
Monica

1
@ माइकपार्ट्रिज: मैं लिंक की सामग्री से अवगत हूं, लेकिन यह अभी भी उदाहरण के लिए पैरामीटर मूल्यांकन को नहीं रोक पाएगा। कारण बाइट पैरामीटराइज़्ड लॉगिंग अधिक निष्पादन योग्य है क्योंकि लॉग संदेश का प्रसंस्करण घटित नहीं होगा (स्ट्रिंग विशेष रूप से संक्षिप्त)। हालांकि, किसी भी विधि कॉल को एक पैरामीटर के रूप में पारित होने पर निष्पादित किया जाएगा। तो, आपके उपयोग के मामले के आधार पर, ब्लॉक उपयोगी हो सकते हैं। और जैसा कि पोस्ट में उल्लेख किया गया है, वे आपके लिए केवल डिबग स्तर सक्षम होने पर अन्य डिबग संबंधित गतिविधियों (केवल लॉगिंग नहीं) को समूह बनाने के लिए भी उपयोगी हो सकते हैं।
ज्येष्ठ

1
@ हाइलम - यह सच है, मेरी गलती है।
माइक पार्टरिज

2

लॉगिंग फ्रेमवर्क का उपयोग करें

अधिकांश समय एक स्थिर कारखाना विधि होती है

private static final Logger logger = Logger.create("classname");

तब आप अपने लॉगिंग कोड को विभिन्न स्तरों के साथ आउटपुट कर सकते हैं:

logger.warning("error message");
logger.info("informational message");
logger.trace("detailed message");

फिर एक एकल फ़ाइल होगी जहाँ आप यह परिभाषित कर सकते हैं कि लॉग आउटपुट के लिए प्रत्येक वर्ग के लिए कौन से संदेश लिखे जाने चाहिए (फ़ाइल या स्टेंडर)


1

यह वही है जो log4j या नए slf4j जैसे लॉगिंग फ्रेमवर्क के लिए है। वे आपको महान विस्तार से लॉगिंग को नियंत्रित करने की अनुमति देते हैं, और एप्लिकेशन चलने पर भी इसे कॉन्फ़िगर करते हैं।


0

लॉगिंग फ्रेमवर्क निश्चित रूप से जाने का रास्ता है। हालाँकि, आपके पास एक अच्छा टेस्ट सूट भी होना चाहिए। अच्छा परीक्षण कवरेज अक्सर सभी को एक साथ डिबग आउटपुट की आवश्यकता को समाप्त कर सकता है।


यदि आप लॉगिंग फ्रेमवर्क का उपयोग करते हैं और डिबग लॉगिंग उपलब्ध है - एक समय आएगा जब यह आपको वास्तव में खराब दिन होने से बचाएगा।
Fortyrunner

1
मैंने नहीं कहा कि आपको लॉगिंग नहीं करनी चाहिए। मैंने कहा कि आपको पहले टेस्ट करवाना होगा।
दिमा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.