अपने जीवन में पहली बार मैं अपने आप को एक ऐसी स्थिति में पाता हूँ जहाँ मैं एक जावा एपीआई लिख रहा हूँ जो कि खुला हुआ होगा। उम्मीद है कि कई अन्य परियोजनाओं में शामिल किया जाएगा।
लॉगिंग के लिए मैंने (और वास्तव में मैं जिन लोगों के साथ काम करता हूं) हमेशा JUL (java.util.log) का उपयोग किया है और इसके साथ कभी कोई समस्या नहीं थी। हालाँकि अब मुझे और अधिक विस्तार से समझने की आवश्यकता है कि मुझे अपने एपीआई विकास के लिए क्या करना चाहिए। मैंने इस पर कुछ शोध किया है और मुझे जो जानकारी मिली है उससे मैं और अधिक भ्रमित हो गया हूं। इसलिए यह पद।
चूँकि मैं JUL से आता हूँ, मैं उस पर पक्षपाती हूँ। बाकी मेरा ज्ञान इतना बड़ा नहीं है।
मैंने जो शोध किया है उससे मैं इन कारणों से सामने आया हूं कि लोग JUL को पसंद क्यों नहीं करते हैं:
"मैंने जावा में विकसित करना शुरू कर दिया था, जब सूरज ने JUL को रिलीज़ किया था, उससे पहले यह मेरे लिए आसान था कि मैं कुछ नया सीखने के बजाय लॉगिंग-फ्रेमवर्क-एक्स को जारी रखूं" । हम्म। मैं मजाक नहीं कर रहा, यह वास्तव में लोग क्या कहते हैं। इस तर्क के साथ हम सभी COBOL कर सकते हैं। (हालांकि मैं निश्चित रूप से यह खुद को एक आलसी दोस्त होने से संबंधित कर सकता हूं)
"मुझे JUL में लॉगिंग स्तरों के नाम पसंद नहीं हैं" । ठीक है, गंभीरता से, यह सिर्फ एक नई निर्भरता को पेश करने के लिए पर्याप्त कारण नहीं है।
"मुझे JUL से आउटपुट का मानक प्रारूप पसंद नहीं है" । हम्म। यह सिर्फ कॉन्फ़िगरेशन है। आपको कुछ भी कोड-वार करने की आवश्यकता नहीं है। (सच है, पुराने दिनों में वापस आपको इसे सही करने के लिए अपना फॉर्मैटर क्लास बनाना पड़ा होगा)।
"मैं अन्य पुस्तकालयों का उपयोग करता हूं जो लॉगिंग-फ्रेमवर्क-एक्स का भी उपयोग करते हैं, इसलिए मैंने सोचा कि बस उस एक का उपयोग करना आसान है" । यह एक गोल तर्क है, है ना? 'सब लोग' लॉगिंग-फ्रेमवर्क-एक्स का उपयोग क्यों करता है और JUL का नहीं?
"हर कोई लॉगिंग-फ्रेमवर्क-एक्स का उपयोग कर रहा है" । यह मेरे लिए सिर्फ उपरोक्त का एक विशेष मामला है। बहुमत हमेशा सही नहीं होता है।
तो असली बड़ा सवाल यह है कि JUL क्यों नहीं? । यह क्या है मुझे याद किया? लॉगिंग facades (SLF4J, JCL) के लिए raison d'être यह है कि कई लॉगिंग कार्यान्वयन ऐतिहासिक रूप से मौजूद हैं और इसका कारण वास्तव में JUL से पहले के युग में वापस जाता है जैसा कि मैं इसे देखता हूं। यदि JUL सही था, तो लॉगिंग facades मौजूद नहीं होगा, या क्या? मामलों को और अधिक भ्रामक बनाने के लिए JUL कुछ हद तक स्वयं एक मुखौटा है, जिससे हैंडलर, फॉर्मेटर्स और यहां तक कि LogManager को स्वैप किया जा सकता है।
एक ही चीज़ (लॉगिंग) करने के कई तरीकों को अपनाने के बजाय, हमें यह सवाल नहीं करना चाहिए कि वे पहली जगह में क्यों आवश्यक थे? (और देखें कि क्या वे कारण अभी भी मौजूद हैं)
ठीक है, अब तक के मेरे शोध से कुछ चीजें सामने आई हैं, जिन्हें मैं देख सकता हूं कि JUL के साथ वास्तविक मुद्दे हो सकते हैं :
प्रदर्शन । कुछ का कहना है कि SLF4J में प्रदर्शन बाकी के मुकाबले बेहतर है। यह मुझे समयपूर्व अनुकूलन का मामला लगता है। यदि आपको प्रति सेकंड सैकड़ों मेगाबाइट लॉग इन करने की आवश्यकता है, तो मुझे यकीन नहीं है कि आप वैसे भी सही रास्ते पर हैं। JUL भी विकसित हुआ है और आपने जावा 1.4 पर जो परीक्षण किए हैं वे अब सच नहीं होंगे। आप इसके बारे में यहां पढ़ सकते हैं और इस फिक्स ने इसे जावा 7 में बना दिया है। कई लोग लॉगिंग विधियों में स्ट्रिंग कॉन्फैटन के ओवरहेड के बारे में भी बात करते हैं। हालाँकि टेम्पलेट आधारित लॉगिंग इस लागत से बचा जाता है और यह JUL में भी मौजूद है। व्यक्तिगत रूप से मैं वास्तव में कभी भी टेम्पलेट आधारित लॉगिंग नहीं लिखता। उसके लिए बहुत आलसी। उदाहरण के लिए अगर मैं JUL के साथ ऐसा करता हूं:
log.finest("Lookup request from username=" + username + ", valueX=" + valueX + ", valueY=" + valueY));
मेरी आईडीई मुझे चेतावनी देगी और अनुमति मांगेगी कि इसे इसे बदलना चाहिए:
log.log(Level.FINEST, "Lookup request from username={0}, valueX={1}, valueY={2}", new Object[]{username, valueX, valueY});
.. जिसे मैं निश्चित रूप से स्वीकार करूंगा। अनुमति प्रदान की गई ! आपके सहयोग के लिए धन्यवाद।
इसलिए मैं वास्तव में ऐसे बयान खुद नहीं लिखता, जो आईडीई द्वारा किया जाता है।
प्रदर्शन के मुद्दे पर निष्कर्ष में मुझे ऐसा कुछ भी नहीं मिला जो यह सुझाव दे कि प्रतियोगिता की तुलना में JUL का प्रदर्शन ठीक नहीं है।
वर्गपथ से विन्यास । आउट-ऑफ-द-बॉक्स JUL क्लासपाथ से कॉन्फ़िगरेशन फ़ाइल लोड नहीं कर सकता है। यह ऐसा करने के लिए कोड की कुछ पंक्तियाँ है । मैं देख सकता हूं कि यह कष्टप्रद क्यों हो सकता है लेकिन समाधान छोटा और सरल है।
आउटपुट हैंडलर्स की उपलब्धता । जूल 5 आउटपुट हैंडलर आउट-ऑफ-द-बॉक्स के साथ आता है: कंसोल, फ़ाइल स्ट्रीम, सॉकेट और मेमोरी। इन्हें बढ़ाया जा सकता है या नए लिखे जा सकते हैं। उदाहरण के लिए यह UNIX / Linux Syslog और Windows इवेंट लॉग में लिखा जा सकता है। मुझे व्यक्तिगत रूप से इसकी आवश्यकता कभी नहीं थी और न ही मैंने इसका उपयोग देखा है, लेकिन मैं निश्चित रूप से इससे संबंधित हूं कि यह एक उपयोगी विशेषता क्यों हो सकती है। लॉगबैक उदाहरण के लिए Syslog के लिए एक परिशिष्ट के साथ आता है। फिर भी मैं यह तर्क दूंगा कि
- आउटपुट गंतव्यों की जरूरतों का 99.5% JUL के आउट-ऑफ-द-बॉक्स में शामिल है।
- JUL के शीर्ष पर कस्टम हैंडलर द्वारा विशेष जरूरतों को पूरा किया जा सकता है, बजाय इसके कि कुछ और के ऊपर। मेरे लिए ऐसा कुछ नहीं है जो यह बताता है कि JUL के लिए Syslog आउटपुट हैंडलर लिखने में अधिक समय लगता है, क्योंकि यह किसी अन्य लॉगिंग फ्रेमवर्क के लिए है।
मैं वास्तव में चिंतित हूँ कि कुछ ऐसा है जिसकी मैंने अनदेखी की है। JUL के अलावा लॉगिंग facades और लॉगिंग कार्यान्वयन का उपयोग इतना व्यापक है कि मुझे इस निष्कर्ष पर आना होगा कि यह मुझे है जो अभी समझ में नहीं आता है। यह पहली बार नहीं होगा, मुझे डर है। :-)
तो मुझे अपने एपीआई के साथ क्या करना चाहिए? मैं चाहता हूं कि यह सफल हो। मैं निश्चित रूप से सिर्फ "प्रवाह के साथ जा सकता हूं" और SLF4J (जो इन दिनों सबसे लोकप्रिय लगता है) को लागू करता है, लेकिन अपने स्वयं के लिए मुझे अभी भी ठीक से समझने की आवश्यकता है कि आज के जूल के साथ क्या गलत है जो सभी फ़ज़ल को वारंट करता है? क्या मैं अपनी लाइब्रेरी के लिए JUL चुनकर खुद को तोड़फोड़ करूंगा?
परीक्षण प्रदर्शन
(07- JUL-2012 पर nolan600 द्वारा जोड़ा गया अनुभाग)
SLF4J के पैराड्राइज़ेशन के बारे में Ceki से एक संदर्भ नीचे है जो कि JUL की तुलना में 10 गुना या अधिक तेज़ है। इसलिए मैंने कुछ सरल परीक्षण करना शुरू कर दिया है। पहली नज़र में दावा निश्चित रूप से सही है। यहाँ प्रारंभिक परिणाम हैं (पर पढ़ें!):
- निष्पादन समय SLF4J, बैकएंड लॉगबैक: 1515
- निष्पादन समय SLF4J, बैक JUL: 12938
- निष्पादन समय JUL: 16911
ऊपर दिए गए नंबर msecs हैं इसलिए कम बेहतर है। तो 10 गुना प्रदर्शन अंतर पहले वास्तव में बहुत करीब है। मेरी प्रारंभिक प्रतिक्रिया: यह बहुत कुछ है!
यहाँ परीक्षण का मूल है। जैसा कि एक पूर्णांक देखा जा सकता है और एक स्ट्रिंग को लूप में कस दिया जाता है जिसका उपयोग लॉग स्टेटमेंट में किया जाता है:
for (int i = 0; i < noOfExecutions; i++) {
for (char x=32; x<88; x++) {
String someString = Character.toString(x);
// here we log
}
}
(मैं चाहता था कि लॉग स्टेटमेंट दोनों में एक आदिम डेटा प्रकार (इस मामले में एक int) और एक अधिक जटिल डेटा प्रकार (इस मामले में एक स्ट्रिंग) होना चाहिए। सुनिश्चित करें कि यह मायने रखता है लेकिन आपके पास वहाँ है।)
SLF4J के लिए लॉग स्टेटमेंट:
logger.info("Logging {} and {} ", i, someString);
JUL का लॉग स्टेटमेंट:
logger.log(Level.INFO, "Logging {0} and {1}", new Object[]{i, someString});
जेवीएम को वास्तविक मापी से पहले एक बार निष्पादित एक ही परीक्षण के साथ 'वार्म अप' किया गया था। विंडोज 1.7 पर जावा 1.7.03 का उपयोग किया गया था। SLF4J (v1.6.6) और लॉगबैक (v1.0.6) के नवीनतम संस्करणों का उपयोग किया गया था। Stdout और Stderr को null डिवाइस पर रीडायरेक्ट किया गया था।
हालाँकि, अब सावधान, यह पता चलता है कि JUL अपना अधिकांश समय व्यतीत कर रहा है getSourceClassName()
क्योंकि JUL डिफ़ॉल्ट रूप से आउटपुट में स्रोत वर्ग के नाम को प्रिंट करता है, जबकि Logback नहीं। इसलिए हम सेब और संतरे की तुलना कर रहे हैं। मुझे फिर से परीक्षण करना होगा और लॉगिंग कार्यान्वयन को समान तरीके से कॉन्फ़िगर करना होगा ताकि वे वास्तव में उसी सामान का उत्पादन करें। मुझे हालांकि इस बात पर संदेह है कि SLF4J + लॉगबैक अभी भी शीर्ष पर बाहर आएगा, लेकिन ऊपर दिए गए प्रारंभिक नंबरों से। बने रहें।
Btw: परीक्षण पहली बार मैं वास्तव में SLF4J या Logback के साथ काम किया है। एक सुखद अनुभव। जब आप शुरू कर रहे हों तो JUL निश्चित रूप से बहुत कम स्वागत योग्य है।
परीक्षण प्रदर्शन (भाग 2)
(08-जुलाई -2018 को nolan600 द्वारा जोड़ा गया अनुभाग)
जैसा कि यह पता चलता है कि प्रदर्शन के लिए यह वास्तव में कोई मायने नहीं रखता है कि आपने JUL में अपने पैटर्न को कैसे कॉन्फ़िगर किया है, अर्थात इसमें स्रोत नाम शामिल है या नहीं। मैंने बहुत ही सरल पैटर्न के साथ कोशिश की:
java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"
और इससे उपरोक्त समय बिल्कुल भी नहीं बदला। मेरे प्रोफाइलर ने बताया कि लकड़हारा अभी भी कॉल में बहुत समय बिताता है, getSourceClassName()
भले ही यह मेरे पैटर्न का हिस्सा न हो। पैटर्न कोई फर्क नहीं पड़ता।
इसलिए मैं प्रदर्शन के मुद्दे पर निष्कर्ष निकाल रहा हूं कि कम से कम परीक्षण किए गए टेम्पलेट आधारित लॉग स्टेटमेंट के लिए JUL (स्लो) और SLF4J + लॉगबैक (क्विक) के बीच वास्तविक प्रदर्शन अंतर में लगभग 10 का कारक लगता है। जैसे कैकेई ने कहा।
मैं एक और बात भी देख सकता हूं कि SLF4J की getLogger()
कॉल JUL के डिट्टो की तुलना में बहुत अधिक महंगी है। (95 एमएस बनाम 0.3 एमएस अगर मेरा प्रोफाइल सही है)। यह समझ में आता है। SLF4J को अंतर्निहित लॉगिंग कार्यान्वयन के बंधन पर कुछ समय देना होगा। यह मुझे डराता नहीं है। ये कॉल किसी एप्लिकेशन के जीवनकाल में कुछ दुर्लभ होनी चाहिए। तेजी वास्तविक लॉग कॉल में होनी चाहिए।
अंतिम निष्कर्ष
(08-जुलाई -2018 को nolan600 द्वारा जोड़ा गया अनुभाग)
आपके सभी उत्तर के लिए धन्यवाद। इसके विपरीत जो मैंने शुरू में सोचा था कि मैंने अपने एपीआई के लिए SLF4J का उपयोग करने का निर्णय लिया है। यह कई चीजों और आपके इनपुट पर आधारित है:
यह तैनाती के समय लॉग कार्यान्वयन का चयन करने के लिए लचीलापन देता है।
अनुप्रयोग सर्वर के अंदर चलने पर JUL के विन्यास के लचीलेपन की कमी के मुद्दे।
SLF4J निश्चित रूप से बहुत तेजी से ऊपर विस्तृत रूप से विस्तृत है यदि आप इसे लॉगबैक के साथ जोड़ते हैं। यहां तक कि अगर यह सिर्फ एक मोटा परीक्षण था, तो मुझे यह विश्वास करने का कारण है कि JUL की तुलना में SLF4J + लॉगबैक पर बहुत अधिक प्रयास अनुकूलन में चले गए हैं।
प्रलेखन। SLF4J के लिए प्रलेखन बहुत अधिक व्यापक और सटीक है।
पैटर्न लचीलापन। जैसा कि मैंने परीक्षण किया था कि मैंने JUL की लॉगबैक से डिफ़ॉल्ट पैटर्न की नकल की थी। इस पैटर्न में थ्रेड का नाम शामिल है। यह पता चला है कि JUL इस बॉक्स से बाहर नहीं कर सकता है। ठीक है, मैं इसे अब तक याद नहीं किया है, लेकिन मुझे नहीं लगता कि यह एक ऐसी चीज है जिसे लॉग फ्रेमवर्क से गायब होना चाहिए। अवधि!
अधिकांश (या कई) जावा परियोजनाएं आज मावेन का उपयोग करती हैं, इसलिए एक निर्भरता जोड़ना बहुत बड़ी बात नहीं है, खासकर अगर वह निर्भरता स्थिर हो, यानी लगातार अपने एपीआई को नहीं बदलती है। यह SLF4J के लिए सही प्रतीत होता है। इसके अलावा SLF4J जार और दोस्त आकार में छोटे हैं।
तो अजीब बात यह है कि SLF4J के साथ थोड़ा काम करने के बाद मैं वास्तव में JUL से काफी परेशान हो गया था। मुझे अभी भी अफसोस है कि यह JUL के साथ इस तरह से होना चाहिए। JUL एकदम सही है, लेकिन इस तरह का काम करता है। बस बहुत अच्छी तरह से पर्याप्त नहीं है। Properties
उदाहरण के बारे में भी यही कहा जा सकता है लेकिन हम अमूर्तता के बारे में नहीं सोचते हैं कि लोग अपने स्वयं के विन्यास पुस्तकालय में प्लग कर सकते हैं और आपके पास क्या है। मुझे लगता है कि इसका कारण Properties
बार के ठीक ऊपर आता है जबकि विपरीत आज के JUL के लिए सही है ... और अतीत में यह शून्य पर आया था क्योंकि यह मौजूद नहीं था।
java.lang.System.Logger
, जो कि एक इंटरफ़ेस है , जिसे आप जो भी वास्तविक लॉगिंग फ्रेमवर्क चाहते हैं, उस तक रीडायरेक्ट किया जा सकता है, जब तक कि वह फ्रेमवर्क पकड़ा गया और उस इंटरफ़ेस का कार्यान्वयन प्रदान करता है। संशोधन के साथ संयुक्त, आप एक JRE युक्त बंडल के साथ एक आवेदन भी कर सकते हैं java.util.logging
, अगर आप एक अलग रूपरेखा पसंद करते हैं।