2012-02-03 6 views
11

हमारा उत्पादन एप्लिकेशन एक त्रुटि दर्ज करता है जब यह एक टीसीपी/आईपी कनेक्शन स्थापित करने में विफल रहता है। चूंकि यह लगातार कनेक्शन को पुनः प्रयास कर रहा है, इसलिए यह वही त्रुटि संदेश लॉग ऑन करता है। और इसी प्रकार, एप्लिकेशन में अन्य चल रहे घटक एक त्रुटि लूप में आ सकते हैं यदि कुछ रीयलटाइम संसाधन समय के लिए अनुपलब्ध है।log4j: दोहराव वाले लॉग संदेशों को रोकने के लिए मानक तरीका?

क्या एक ही त्रुटि लॉग होने की संख्या को नियंत्रित करने के लिए कोई मानक दृष्टिकोण है? (हम log4j का उपयोग कर रहे हैं, इसलिए अगर इसे संभालने के लिए log4j के लिए कोई एक्सटेंशन है, तो यह सही होगा।)

+0

चेक इस लिंक http://stackoverflow.com/questions/8359839/how-to-log-repeated-warnings-only-once –

+1

@SajanChandran: मैं समझ मैं "मेरे अपने रोल" सकता है, लेकिन उम्मीद थी कि यह एक आम समस्या थी, कि पहले से ही मानक समाधान/सर्वोत्तम अभ्यास था। अगर मैं इसे कोड करता हूं, तो मैं सबसे अधिक संभावना लॉग 4j कक्षा का विस्तार करूंगा ताकि यह कोडिंग के बजाय कॉन्फ़िगरेशन कार्य हो। –

+0

यह एक अच्छा पहला कदम हो सकता है: http://logging.apache.org/log4j/2.x/manual/filters.html#BurstFilter/ - हो सकता है कि आप इस तरह के कोड को एकीकृत करने के लिए अपना स्वयं का फ़िल्टर लिख सकें उत्तर: https://stackoverflow.com/a/37619797/1520422 –

उत्तर

2

प्रत्येक बार जब आप त्रुटि लॉग करते हैं, तो टाइमस्टैम्प रिकॉर्ड करके इसे नियंत्रित करना काफी आसान होगा, और फिर केवल अगली बार लॉग इन करना अगर एक निश्चित अवधि समाप्त हो गई है।

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

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

3

मैंने अभी एक जावा क्लास बनाई है जो log4j का उपयोग करके इस सटीक समस्या को हल करती है। जब मैं एक संदेश लॉग इन करना चाहते, मैं सिर्फ कुछ इस तरह करते हैं:

LogConsolidated.log(logger, Level.WARN, 5000, "File: " + f + " not found.", e); 

बजाय:

logger.warn("File: " + f + " not found.", e); 

कौन सा यह 1 समय की एक अधिकतम कभी 5 सेकंड के लिए लॉग इन करता है, और प्रिंट कितनी बार यह लॉग होना चाहिए था (उदाहरण | x53 |)। जाहिर है, आप इसे बना सकते हैं ताकि आपके पास कई पैरामीटर न हों, या log.warn या कुछ करके स्तर को खींचें, लेकिन यह मेरे उपयोग के मामले के लिए काम करता है।

import java.util.HashMap; 

import org.apache.log4j.Level; 
import org.apache.log4j.Logger; 

public class LogConsolidated { 

    private static HashMap<String, TimeAndCount> lastLoggedTime = new HashMap<>(); 

    /** 
    * Logs given <code>message</code> to given <code>logger</code> as long as: 
    * <ul> 
    * <li>A message (from same class and line number) has not already been logged within the past <code>timeBetweenLogs</code>.</li> 
    * <li>The given <code>level</code> is active for given <code>logger</code>.</li> 
    * </ul> 
    * Note: If messages are skipped, they are counted. When <code>timeBetweenLogs</code> has passed, and a repeat message is logged, 
    * the count will be displayed. 
    * @param logger Where to log. 
    * @param level Level to log. 
    * @param timeBetweenLogs Milliseconds to wait between similar log messages. 
    * @param message The actual message to log. 
    * @param t Can be null. Will log stack trace if not null. 
    */ 
    public static void log(Logger logger, Level level, long timeBetweenLogs, String message, Throwable t) { 
     if (logger.isEnabledFor(level)) { 
      String uniqueIdentifier = getFileAndLine(); 
      TimeAndCount lastTimeAndCount = lastLoggedTime.get(uniqueIdentifier); 
      if (lastTimeAndCount != null) { 
       synchronized (lastTimeAndCount) { 
        long now = System.currentTimeMillis(); 
        if (now - lastTimeAndCount.time < timeBetweenLogs) { 
         lastTimeAndCount.count++; 
         return; 
        } else { 
         log(logger, level, "|x" + lastTimeAndCount.count + "| " + message, t); 
        } 
       } 
      } else { 
       log(logger, level, message, t); 
      } 
      lastLoggedTime.put(uniqueIdentifier, new TimeAndCount()); 
     } 
    } 

    private static String getFileAndLine() { 
     StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); 
     boolean enteredLogConsolidated = false; 
     for (StackTraceElement ste : stackTrace) { 
      if (ste.getClassName().equals(LogConsolidated.class.getName())) { 
       enteredLogConsolidated = true; 
      } else if (enteredLogConsolidated) { 
       // We have now file/line before entering LogConsolidated. 
       return ste.getFileName() + ":" + ste.getLineNumber(); 
      } 
     } 
     return "?"; 
    }  

    private static void log(Logger logger, Level level, String message, Throwable t) { 
     if (t == null) { 
      logger.log(level, message); 
     } else { 
      logger.log(level, message, t); 
     } 
    } 

    private static class TimeAndCount { 
     long time; 
     int count; 
     TimeAndCount() { 
      this.time = System.currentTimeMillis(); 
      this.count = 0; 
     } 
    } 
} 
+0

ध्यान दें कि मानचित्र का उपयोग थ्रेड सुरक्षित नहीं है। इसके अलावा, वास्तविक लॉगिंग करने वाले अन्य मामले के परिणामस्वरूप एक ही समय में एक ही त्रुटि को लॉगिंग करने वाले दो धागे हो सकते हैं। –

+0

सच है, यह संभव है कि कोड के ठीक उसी पंक्ति से लॉगर को कॉल करने वाले दो थ्रेड, लॉगर को एक ही चीज़ को दो बार लॉग इन कर सकें। मैं मैप थ्रेड को एक्सेस तक सुरक्षित बनाकर इसे ठीक कर सकता हूं, लेकिन मैं डुप्लिकेट लॉग संदेश की संभावना रखने के लिए प्रदर्शन हिट से गुजर जाऊंगा। इस पूरी बात का मुख्य विचार स्पैमिंग संदेशों को काटना है जब ऐप खराब स्थिति में आता है तो लॉग को पचाना आसान होता है। मुद्दों को इंगित करने के लिए धन्यवाद, मैं वास्तव में इसकी सराहना करता हूं! – 11101101b

+0

बग अलर्ट: lastTimeAndCount.time को प्रत्येक लॉग संदेश के बाद रीसेट किया जाना चाहिए अन्यथा समय के बाद + डेल्टा - आप सभी संदेशों को लॉगिंग करना समाप्त कर देते हैं। – rjha94

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