2011-12-09 8 views
24

मुझे यहाँ एक बहस में मदद .. :)slf4j के साथ भी, क्या आप अपनी लॉगिंग की रक्षा कर सकते हैं?

slf4j साइट यहाँ http://www.slf4j.org/faq.html#logging_performance इंगित करता है कि पैरामिट्रीकृत लॉगिंग की वजह से प्रवेश करने गार्ड आवश्यक नहीं हैं। अर्थात। बजाय लेखन की:

if(logger.isDebugEnabled()) { 
    logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); 
} 

आप के साथ भाग प्राप्त कर सकते हैं:

Object entry = new SomeObject(); 
logger.debug("The entry is {}.", entry); 

यह वास्तव में ठीक है, या यह (कम यद्यपि) उठाना पड़ता स्थिर स्ट्रिंग है जो पता लगाने विधि के लिए पारित किया है बनाने की लागत ..?

उत्तर

33

मैं दूसरे दृष्टिकोण

वास्तव में क्या parametrized प्रवेश के लाभ है से मेरे दो सेंट डाल करने की कोशिश करेंगे?

तुम बस toString() मंगलाचरण और स्ट्रिंग संयोजन स्थगित जब तक वास्तव में जरूरत है, जो तुम सच में संदेश लॉग इन करना होगा जब। यह उस विशेष लॉगिंग ऑपरेशन को अक्षम होने पर प्रदर्शन को अनुकूलित करता है। यदि सुनिश्चित नहीं है तो source code for SLF4J देखें।

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

सं

जो मामलों में प्रवेश गार्ड उपयोग की हो सकता है?

जब अन्य संभावित महंगे संचालन होते हैं।

उदाहरण के लिए (मामले इस विशेष प्रवेश आपरेशन अक्षम किया गया है में), अगर हम कोई प्रवेश गार्ड है

logger.debug("User: {}", getUserService().getCurrentUser()); 
  1. हम लागत obj = getUserService().getCurrentUser()
  2. से भुगतान करने होंगे हम बचत होगी "User name: " + obj.toString()

की लागत यदि हम उपयोग लॉगिंग गार्ड:

if (logger.isDebugEnabled()) { 
    logger.debug("User: {}", getUserService().getCurrentUser()); 
} 
  1. हम का भुगतान करेगा logger.isDebugEnabled()
  2. की लागत हम लागत की बचत होगी obj = getUserService().getCurrentUser()
  3. से हम "User name: " + obj.toString()
से लागत की बचत होगी

बाद के सी में एएसई, जब हम इस विशेष लॉगिंग ऑपरेशन को सक्षम करते हैं, तो हम isDebugEnabled() को दो बार जांचने की कीमत पर दोनों लागतों को बचाएंगे।

नोट: यह केवल एक उदाहरण है, यहां अच्छे/बुरे प्रथाओं पर बहस करने की कोशिश नहीं कर रहा है।

+0

धन्यवाद fgelz, यह सबसे स्पष्ट स्पष्टीकरण है इसलिए मैंने अपना दिमाग जवाब बदल दिया। बनाता है आपको लगता है सभी विभिन्न चौखटे के बावजूद, वहां अभी भी प्रवेश दुनिया में नवाचार के लिए कमरा, महंगा आपरेशन टाल के संदर्भ में है कि .. शायद प्रतिनिधियों –

+0

@MarkD JDK 8 परियोजना लैम्ब्डा नवाचार (http मदद करने के लिए जा रहा है के साथ: // openjdk .java.net/परियोजनाओं/लैम्ब्डा /) – fglez

+0

तुम भी है कि (जैसे logger.debug (स्ट्रिंग, वस्तु ..) एक varargs विधि बुला वास्तव में कवर logger.debug (स्ट्रिंग, नई वस्तु [के तहत कर रही है के बारे में पता होना चाहिए। ..])। इसलिए यदि आप कॉल को लपेट नहीं पाते हैं, तो आप इस विधि को पार करते समय हर बार एक नया ऑब्जेक्ट सरणी बना रहे हैं (फिर भी निपटान कर रहे हैं), भले ही आप सामग्री को कभी नहीं लिखते। अगर आपके पास अत्यधिक प्रदर्शन प्रणाली है या मेमोरी प्रेशर का अनुभव करें, तो यह समय के साथ बना सकता है; और logger.isDebugEnabled() कॉल को एक सभ्य जेआईटी द्वारा रेखांकित किया जाएगा यदि एसएलएफ 4 जे इसे एक और दो तर्कों के लिए माहिर करता है, लेकिन अधिक के लिए आपको मिलेगा आधुनिक वर्ल के साथ – AlBlue

2

कृपया, if कथन का उपयोग नहीं है क्योंकि हर बार जब मैं इस

if (logger.isDebug()) { 
    logger.debug("Of course it's debug {}", sadFace); 
} 

मैं रोना की तरह कोड को देखो।

मुझे आशा है कि स्थिर स्ट्रिंग बनाने की लागत 99% उपयोगकर्ताओं के लिए बहुत कम है।

+1

slf4j '{0}' निर्माण का उपयोग नहीं करता है। –

+0

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

15

उन सभी if(logger.isDebugEnabled()) {} को लिखना और पढ़ना संभवतः उतना ही समय लगेगा जितना वे आपको बचाते हैं।

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

यह कोड को भी बंद कर देता है।

प्रैक्टिस में, मुझे प्रदर्शन दंड को परेशान करने के लिए पर्याप्त बड़ा नहीं मिला है।

यदि लॉगिंग आपके लिए बहुत धीमी है, तो एक गैर-अवरोधक एपेंडर लिखें जो लॉग घटनाओं को केवल कुछ चेक के बिना कतार में धक्का देता है और उन्हें संसाधित करने के लिए पृष्ठभूमि थ्रेड का उपयोग करता है।

पृष्ठभूमि: मानक परिशिष्ट सभी सिंक्रनाइज़ किए गए हैं इसलिए बहु-थ्रेडेड एप्लिकेशन में लॉगिंग करने से बहुत सारे छोटे विराम हो सकते हैं जहां सभी थ्रेड फ़ाइल में लॉग संदेश के लिए प्रतीक्षा करते हैं।

+0

धन्यवाद जो मैं सोचता हूं .. यह देखने के लिए इंतजार कर रहा है कि आम सहमति क्या है कि मैं आपको प्लस देता हूं :) मुझे उन परिशिष्टों के बारे में टिप पसंद है जो हमारे लिए एक समस्या हो सकती हैं। –

+0

दोनों "लॉग विधि को कॉल करना" और "कॉलिंग isDebugEnabled()" ** वास्तव में स्वतंत्र हो सकता है ** कुछ जेआईटी अनुकूलन मुझे लगता है। मुझे यकीन नहीं है, लेकिन अगर sl4jf के लिए वास्तविक उच्च प्रदर्शन कार्यान्वयन प्रदान करने वाला व्यक्ति होगा, तो मैं विकलांग स्तरों के लिए समय पर नो-ऑप विधि के साथ कार्यान्वयन करता हूं, ताकि जेआईटी कॉल को हटा सके। –

4

इस तरह की एक प्रवेश बयान के साथ समस्या:

logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i])); 

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

logger.debug("The entry is {}.", entry); 

तो यह अनावश्यक रूप से एक String जाता है कि इस्तेमाल कभी नहीं का निर्माण करने की जरूरत नहीं है, और जांच आवश्यक नहीं है; बस एक विधि के लिए तर्क पारित करने के लिए बहुत अधिक ऊपरी नहीं है।

ध्यान दें कि यदि आपके पास लॉगिंग कथन में तर्कों के लिए अपेक्षाकृत महंगी अभिव्यक्तियां हैं, तो यह पहले भी लॉगिंग स्तर की जांच करने के लिए फायदेमंद हो सकती है।

+0

आप अज्ञात वर्ग में toString() विधि में उन्हें महंगे अभिव्यक्तियों को संभाल सकते हैं, इसलिए वास्तव में उनका मूल्यांकन नहीं होने तक उनका मूल्यांकन नहीं किया जाता है। –

+0

@ ThorbjørnRavnAndersen हां, लेकिन यह कोड को काफी वर्बोज़ बना देगा। – Jesper

5

स्ट्रिंग निर्माण के कारण गार्ड का उपयोग नहीं किया जाता है।

इसके बजाए, आमतौर पर इसे संभावित रूप से महंगा तर्क अभिव्यक्ति से बचने के लिए उपयोग किया जाता है, जैसे entry[i].retrieveExtendedDebugInformation().formatNicely()। इसके लिए, लॉगबैक सुनिश्चित करता है कि तर्क का मूल्यांकन केवल तभी किया जाता है जब लॉग संदेश वास्तव में मुद्रित होता है, जबकि log4j हमेशा डीबग() को कॉल करने से पहले तर्क का मूल्यांकन करता है।

यहां एकमात्र उम्मीदवार String.valueOf(entry[i]) है, जो कि बहुत महंगा नहीं है, इसलिए आप यह तर्क दे सकते हैं कि यह गार्ड पूरी तरह से असफल है।

+1

ठीक है - यह समझ में आता है और चीजों पर एक और विचार है। तो आपकी राय में यह रक्षा करने के लिए एक निर्णय कॉल है कि क्या रक्षा करना है, और गार्डिंग का उपयोग केवल अपेक्षाकृत दुर्लभ (महंगी) परिचालनों पर किया जाना चाहिए? .. उन परिचालनों की मात्रा को कम करने वाले पैरामीटर का परिचय .. –

+0

हां, और कितना महंगा है ऑपरेशन गार्डिंग अक्सर लूप के अंदर बयानों का पता लगाने के लिए समझ में आता है। कोई भी तर्क दे सकता है कि यदि आपके डीबग स्टेटमेंट इतने महंगे हैं कि जब आप उच्च लॉग स्तर पर होते हैं तो भी कक्षा को धीमा कर देते हैं, तो आप log.debug का उपयोग नहीं कर रहे हैं, विशेष रूप से, आप शायद ' हालत) {log.debug (complicatedExpression); doSomething();} 'जबकि आपको' log.debug (जटिल एक्स्प्रेसियन) करना चाहिए; जबकि (हालत) {log.trace (simpleExpression); DoSomething();} '। लेकिन मैं कोई उत्साह नहीं हूं, मैं मानता हूं कि मैं अक्सर इसके बजाय एक गार्ड लिख रहा हूं। – wallenborn

+0

"बहुत महंगा नहीं" अभी भी बहुत सारे लॉग-स्टेटमेंट वाले प्रोग्राम के लिए अंतर बनाने के लिए काफी महंगा है। –

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