2009-02-19 13 views
22

मैं एक निदान लॉग होना चाहता हूं जो डेटा प्रबंधन के कई कार्यों द्वारा उत्पादित किया जाता है। ये कार्य एकाधिक धागे में हो सकते हैं। प्रत्येक कार्य को लॉग में एक तत्व (संभवतः उपखंडों के साथ) लिखने की आवश्यकता होती है; अंदर आ जाओ और जल्दी से बाहर निकलें। यदि यह एक एकल कार्य की स्थिति थी तो मैं XMLStreamWriter का उपयोग करता हूं क्योंकि यह स्मृति में एक गुब्बारे वाले XML दस्तावेज़ को पकड़ने के बिना सादगी/कार्यक्षमता के लिए सबसे अच्छा मिलान जैसा लगता है।एकाधिक धागे से जावा लॉगिंग के लिए सर्वोत्तम अभ्यास?

लेकिन यह एक एकल कार्य स्थिति नहीं है, और मुझे यकीन है कि कैसे सबसे अच्छा यकीन है कि यह "threadsafe", वह जगह है जहाँ "threadsafe" इस आवेदन में अर्थ है कि प्रत्येक लॉग तत्व सही ढंग से करने के लिए लॉग लिखा जाना चाहिए बनाने के लिए नहीं कर रहा हूँ और क्रमशः (एक के बाद एक और किसी भी तरह से interleaved नहीं)।

कोई सुझाव? मेरे पास एक अस्पष्ट अंतर्ज्ञान है कि जाने का तरीका लॉग तत्वों की कतार का उपयोग करना है (प्रत्येक व्यक्ति को जल्दी से उत्पादित करने में सक्षम है: मेरा एप्लिकेशन वास्तविक काम करने में व्यस्त है जो प्रदर्शन-संवेदनशील है), और एक अलग धागा है जो लॉग को संभालता है तत्व और उन्हें एक फ़ाइल में भेजता है ताकि लॉगिंग उत्पादकों को बाधित न करे।

लॉगिंग आवश्यक रूप से एक्सएमएल होना आवश्यक नहीं है, लेकिन मैं इसे संरचित और मशीन-पठनीय बनाना चाहता हूं।

संपादित करें: मैंने उद्धरणों में "थ्रेडसेफ" रखा है। Log4j स्पष्ट विकल्प (मेरे लिए नया लेकिन समुदाय के लिए पुराना) प्रतीत होता है, क्यों पहिया को फिर से शुरू करें ...

+0

मुझे एक ही समस्या है, लेकिन वास्तविक समय में लॉग प्रदर्शित करने की आवश्यकता नहीं है (केवल सभी धागे निष्पादित करने के बाद)। मेरा समाधान प्रत्येक संदेश की शुरुआत में सिस्टम समय जोड़ना है, और उस समय उन्हें सॉर्ट करना है। – Fuhrmanator

+0

सिस्टम समय सभी के बाद विश्वसनीय नहीं है - कुछ ऑपरेशन इतने करीब हैं कि उनके पास मिलीसेकंड में एक ही टाइमस्टैम्प है। सॉर्टिंग के परिणामस्वरूप ऑर्डर बदल सकता है। तो, मैंने कोशिश की एक और चीज Colllections.synchronizedList() का उपयोग संदेशों के स्ट्रिंग्स के एक ArrayList को लपेटने के लिए किया था। स्ट्रिंग में जोड़ना एक टाइमस्टैम्प दिखाता है कि यह तरीका भी सही नहीं है। मेरे मामले में कुछ संदेश ऑर्डर से बाहर थे (एक या दो मिलीसेकंड द्वारा), लेकिन संभवतः यह सिंक्रनाइज़ सूची में ऐड() कॉल के लिए कतार में देरी के कारण है। – Fuhrmanator

उत्तर

21

Log4j जैसे लॉगिंग फ्रेमवर्क का उपयोग करें।

+0

धन्यवाद! दस्तावेज़ों को पढ़ना (http://logging.apache.org/log4j/1.2/manual.html) अब ... –

+2

थ्रेड नाम – chburd

+3

लॉग इन करने के लिए log4j रूपांतरणपटल में '% t' अभिव्यक्ति का उपयोग करना सुनिश्चित करें I लगता है कि log4j लॉगिंग थ्रेडसेफ बनाता है। थ्रेडसेफ द्वारा मेरा मतलब है कि जिस क्रम में लॉगिंग मुद्रित की जाती है वह शेड्यूलर के किसी ऑर्डरिंग के लिए समान होनी चाहिए। मेरा मानना ​​है कि आपको अभी भी लॉगिंग के लिए थ्रेडसेफ होने के लिए सिंक्रनाइज़ेशन और लॉकिंग का उपयोग करना होगा। कोई भी पुष्टि/अस्वीकार करना चाहता है? – jbu

3

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

+0

मुझे उनके कारणों पर डाउनवॉटर टिप्पणी देखना अच्छा लगेगा। बेशक एक लॉगिंग फ्रेमवर्क का उपयोग करना शायद सबसे अच्छा विकल्प है, लेकिन यदि आप इसे स्वयं करना चाहते हैं, तो आपको सिंक्रनाइज़ेशन का उपयोग करना होगा ... – jpfollenius

+0

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

+0

इसके अलावा, यदि आप इसे * कर रहे थे तो जावा में ऐसा करने का सबसे अच्छा तरीका शायद आपके पास एक प्रस्ताव कर रहे विभिन्न थ्रेड होंगे या ब्लॉकिंगक्यूयू पर डालेंगे, और एक लॉगर थ्रेड जो लूप में लेता है और उन्हें लिखता है जितनी जल्दी हो सके लॉग फ़ाइल में बाहर जा सकते हैं। 'सिंक्रनाइज़' के साथ गड़बड़ करने की कोई ज़रूरत नहीं है। –

4

लॉग 4 जैसे लॉगिंग फ्रेमवर्क का उपयोग करें।

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

3

log4j कई वर्षों से जावा लॉगिंग के लिए मानक है और यह मानक रहा है। लेकिन यदि आप बाहरी निर्भरता की कल्पना नहीं करते हैं तो java.util.logging पैकेज एक स्वीकार्य समाधान प्रदान करता है।

+1

निश्चित जुल एक विकल्प है, लेकिन मुझे यकीन नहीं है कि मैं इसे पूरी तरह से अच्छा कहूंगा। यह मेरी राय में सबसे अच्छा टाल गया है, और हां मैंने सीखा कि कठिन तरीका, इसे इस्तेमाल करने के लिए मजबूर होना। –

+0

आप ऐसा क्यों कहते हैं? एनडीसी के लिए – LoveMeow

4

एक लॉगिंग फ्रेमवर्क का उपयोग करें जो the NDC pattern के कुछ रूपों को लागू करता है, जैसे Log4J

+1

+1 - और एमडीसी को भी मत भूलना, जो व्यक्तिगत रूप से मुझे एनडीसी से अधिक उपयोगी लगता है। वेबपैप में, मैं एमडीसी में सत्र आईडी जोड़ना चाहता हूं ताकि प्रत्येक लॉग लाइन में उपयोगकर्ता की सत्र आईडी हो। –

0

इसे अपने आप को थ्रेड-सुरक्षित तरीके से विकसित करना मामूली नहीं है, इसलिए आपको वास्तव में मौजूदा लॉगिंग फ्रेमवर्क का उपयोग करना चाहिए जो थ्रेड-सुरक्षित है। सबसे अधिक इस्तेमाल किया जाने वाला एक Log4J है, जो थ्रेड-सुरक्षित है (FAQ देखें)।

20

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

myVariableSum = 0 + myVariable; 
//here comes other thread - Not very likely! 
logger.info("Log some INFO; myVariable has value" + myVariable.toString()); 

आप यह सुनिश्चित करें कि myVariable पल गणना (पहली पंक्ति) से कुछ अन्य धागे से नहीं बदली है प्रदर्शन किया गया था लेकिन विधि प्रवेश करने से पहले कहा जाता था बनाने के लिए किया है। यदि ऐसा होता है, तो आप गंदे मान को लॉग करेंगे जो ऑपरेशन करने के लिए उपयोग नहीं किया गया था लेकिन मान जो किसी अन्य थ्रेड द्वारा असाइन किया गया था।आमतौर पर इसका ख्याल रखा जाता है; उदाहरण के लिए स्थानीय (विधि स्तर) चर अन्य धागे द्वारा बदला नहीं जा सकता है। वैसे भी, अगर आपको लॉगिंग करते समय इस बारे में चिंता करनी है, तो 99% से अधिक आपके प्रोग्राम में पहले से ही गंभीर थ्रेडिंग समस्याएं हैं।
सभी प्रमुख लॉगिंग ढांचे स्वयं "थ्रेडसेफ" हैं जिसका अर्थ है कि उन्हें बहुप्रचारित वातावरण में तैनात किया जा सकता है और आंतरिक रूप से वर्णित एक जैसी समस्याओं को प्रदर्शित नहीं करेगा।
लॉग इन में प्रकट होने के निशान प्राप्त करने के क्रम में वे वास्तव में कॉल के "धारावाहिक" कहते हैं। लॉग लिखना serializing किसी भी multithreaded ऐप पर एक प्रमुख प्रदर्शन बाधा होगी। यदि आप log4j जैसे लॉगिंग फ्रेमवर्क का उपयोग करते हैं, तो सभी धागे से निशान एक ही स्थान पर दिखाई देंगे ताकि वे घटित हों। हालांकि, एक कॉलम आम तौर पर थ्रेड नाम होता है, ताकि आप आसानी से थ्रेड द्वारा अपने लॉग डेटा को फ़िल्टर कर सकें; प्रत्येक धागा कालक्रम क्रम में अपने डेटा लॉग करेगा। इस लिंक को देखें: http://logging.apache.org/log4j/1.2/faq.html#1.7
अंत में, अगर आपको लिखने के लिए सीरियललाइजिंग की आवश्यकता है, तो आप java.util.concurrent.BlockingQueue जैसे किसी प्रकार की संरचना का उपयोग कर सकते हैं।

+1

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

+1

थ्रेड सुरक्षा बनाम serialization के अपने स्पष्टीकरण पर अच्छा काम। – Julie

+0

बहुत अच्छी तरह से +1 समझाया – ADJ

5

मैं Log4J के शीर्ष पर SLF4J का उपयोग करता हूं। parameterized logging कार्यक्षमता विशेष रूप से आकर्षक है यदि आपके पास बहुत सारे लॉगिंग स्टेटमेंट हैं जो उत्पादन वातावरण में अच्छी तरह से बंद हो सकते हैं।

यह java.util.logging के शीर्ष पर भी चलाया जा सकता है या इसका अपना सरल आउटपुट उपयोग कर सकता है।

9

लॉगबैक-क्लासिक का उपयोग करें। यह log4j का एक नया और बेहतर कार्यान्वयन है।

0

यदि आपको करना था, तो आप एकल-लेखक/एकल-पाठक फीफो या कतारों का उपयोग करके अपना खुद का रोल कर सकते हैं।

1

मुझे केवल विशेष लॉग के लिए एक ही समस्या और कार्यान्वयन की मांग थी। मेरे समाधान किया गया था:

  1. मैं एप्लिकेशन की यातायात/मिनट की *2 के आकार के साथ एक blockinglinkedqueue ले लिया।

  2. सभी धागे ऑब्जेक्ट को कतार में डालते हैं और नौकरी खत्म करते हैं।

  3. पृथक Log-Writer अलग-अलग एपेंडर का उपयोग करके log4j फ़ाइल को लिखने के लिए अलग-अलग Log-Writer थ्रेड लेना। इस एपेंडर का उपयोग systemlogs के लिए नहीं किया गया था।

यह सुनिश्चित करता है कि लॉग क्रमशः लिखे गए हैं और हमेशा क्रम में हैं।

यह एप्लिकेशन के प्रदर्शन को प्रभावित नहीं करेगा क्योंकि लॉग लेखन एक पूरी तरह से अलग प्रक्रिया है और एक बाधा उत्पन्न नहीं करेगा।

आप log4j का भी उपयोग कर सकते हैं।

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