बुनियादी लॉगिंग बनाम संरचित लॉगिंग के लाभ


110

हम एक नया ऐप बना रहे हैं और मैं संरचित लॉगिंग को शामिल करना चाहूंगा। मेरा आदर्श सेटअप Serilogहमारे C # कोड के Bunyanलिए और हमारे JS के लिए कुछ होगा । ये खिलाते हैं fluentdऔर फिर किसी भी चीज़ के लिए बाहर जा सकते हैं, मैं शुरू में सोच रहा था elasticsearch + kibana। हमारे पास MySQL डेटाबेस पहले से ही है, इसलिए अल्पावधि में मैं Serilog + Bunyan सेटअप और इसे उपयोग करने के लिए देवताओं को प्राप्त करने में अधिक रुचि रखता हूं और जब हम धाराप्रवाह और बाकी हिस्सों में लाने में थोड़ा अधिक समय लेते हैं तो हम MySQL में लॉग इन कर सकते हैं।

हालांकि, हमारे अधिक अनुभवी कोडर्स में से एक बस कुछ करना पसंद करेगा: log.debug("Disk quota {0} exceeded by user {1}", quota, user);का उपयोग करना log4netऔर फिर MySQL के खिलाफ चुनिंदा बयानों को चलाना जैसे:SELECT text FROM logs WHERE text LIKE "Disk quota";

यह कहा जा रहा है कि लॉगिंग सिस्टम के प्रकार को चुनते समय कौन सा दृष्टिकोण बेहतर है और / या हमें किन चीजों पर विचार करने की आवश्यकता है?


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

2
@ डीटीआई-मैट सेरिलॉग की संरचित लॉगिंग केवल मूल लॉगिंग है, केवल यह उन वस्तुओं को प्रारूपित करता है जिन्हें आप इसे प्रिंट करते हैं - कुछ आप अपने आप को ओवर-राइडिंग करके बहुत आसानी से कर सकते हैं। एक अधिक महत्वपूर्ण पहलू लॉग फ़ाइलों का कॉन्फ़िगरेशन और प्रबंधन है, एक स्ट्रिंग को दूसरे पर प्रारूपित करने का एक तरीका नहीं है, दूसरा प्रदर्शन है। यदि देव log4net का उपयोग करना चाहता है (जो कि एक अच्छी लॉगिंग लिब) है, तो आपकी सेरिलॉग की पसंद (जो शांत दिखती है) उन चीजों में से एक है "समस्या की तलाश में समाधान"।
gbjbaanb

@ DTI- मैट सेरिलॉग को देखने से यह log4net के समान दिखता है। log4net कॉन्फ़िगरेशन पर संरचित लॉग बनाना संभालती है। आपको लॉग संदेशों को खोजने की आवश्यकता नहीं है क्योंकि आपके पास एक तालिका में अतिरिक्त जानकारी कॉन्फ़िगर और लिखी जा सकती है। इसके अलावा log4net को fluentd tipstuff.org/2014/05/… के
RubberChickenLeader

देखो बाहर कुछ मूर्ख हैं जो यहाँ वैचारिक प्रश्नों के विचार को नहीं समझते हैं। अपने ETL क्षमताओं v पर कोड प्राप्त करने के प्रयास में डेटाबेस अनुप्रयोगों की दिशा के बारे में पूछना। v। कोड आपको कुछ गंभीर डाउनवोट मिलेगा। मुझे लगता है कि आपका प्रश्न चॉपिंग ब्लॉक पर भी होगा।
1939 में यूजर 916597

2
@gbjbaanb Serilog उसी तरह से कार्य करता है जैसे कि पाठ के रूप में घटनाओं को प्रस्तुत करते समय log4net, लेकिन यदि आप लॉग को संग्रहित करने के लिए एक संरचित प्रारूप का उपयोग करते हैं, तो यह उन गुणों के नाम गुणों को संबद्ध कर देगा, जो पारित हो चुके हैं (यानी regex के बिना खोज / फ़िल्टर का समर्थन करने के लिए) ) HTH!
निकोलस ब्लमहार्ट

जवाबों:


139

संरचित दृष्टिकोण के साथ दो मौलिक अग्रिम हैं जिन्हें अतिरिक्त प्रयास के बिना (कभी-कभी चरम स्तर के) पाठ लॉग का उपयोग करके अनुकरण नहीं किया जा सकता है।

घटना के प्रकार

जब आप log4net के साथ दो ईवेंट लिखते हैं जैसे:

log.Debug("Disk quota {0} exceeded by user {1}", 100, "DTI-Matt");
log.Debug("Disk quota {0} exceeded by user {1}", 150, "nblumhardt");

ये समान पाठ का उत्पादन करेंगे:

Disk quota 100 exceeded by user DTI-Matt
Disk quota 150 exceeded by user nblumhardt

लेकिन, जहाँ तक मशीन प्रसंस्करण का सवाल है, वे अलग-अलग पाठ की सिर्फ दो पंक्तियाँ हैं।

आप सभी "डिस्क कोटा से अधिक" ईवेंट ढूंढना चाह सकते हैं, लेकिन ईवेंट की तलाश का सरलीकृत मामला like 'Disk quota%'जैसे ही किसी अन्य ईवेंट के रूप में दिखाई देगा, वैसे ही नीचे गिर जाएगा:

Disk quota 100 set for user DTI-Matt

पाठ लॉगिंग उन सूचनाओं को निकाल देता है जो हमारे पास शुरुआत में घटना के स्रोत के बारे में होती हैं, और जब लॉग को आमतौर पर अधिक से अधिक विस्तृत अभिव्यक्ति के साथ पढ़ना होता है, तो इसे फिर से संगठित करना पड़ता है।

इसके विपरीत, जब आप निम्नलिखित दो सेरिलॉग घटनाएँ लिखते हैं:

log.Debug("Disk quota {Quota} exceeded by user {Username}", 100, "DTI-Matt");
log.Debug("Disk quota {Quota} exceeded by user {Username}", 150, "nblumhardt");

ये लॉग 4net संस्करण के समान पाठ आउटपुट का उत्पादन करते हैं, लेकिन पर्दे के पीछे, "Disk quota {Quota} exceeded by user {Username}" संदेश टेम्पलेट दोनों घटनाओं द्वारा किया जाता है।

एक उपयुक्त सिंक के साथ, आप बाद में क्वेरीज़ लिख सकते हैं where MessageTemplate = 'Disk quota {Quota} exceeded by user {Username}'और ठीक उसी तरह की घटनाओं को प्राप्त कर सकते हैं जहां डिस्क कोटा पार किया गया था।

यह हर लॉग घटना के साथ पूरा संदेश टेम्पलेट स्टोर करने के लिए सुविधाजनक हमेशा नहीं है, इसलिए कुछ डूब एक अंकीय में संदेश टेम्पलेट हैश EventTypeमूल्य (जैसे 0x1234abcd), या, आप करने के लिए लॉगिंग पाइप लाइन के लिए एक Enricher जोड़ सकते हैं अपने आप को ऐसा करने के

यह नीचे दिए गए अगले अंतर से अधिक सूक्ष्म है, लेकिन बड़े लॉग वॉल्यूम के साथ काम करते समय बड़े पैमाने पर शक्तिशाली है।

संरचित डेटा

डिस्क स्थान उपयोग के बारे में दो घटनाओं पर विचार करने के बाद, किसी विशेष उपयोगकर्ता के लिए क्वेरी के पाठ लॉग का उपयोग करना काफी आसान हो सकता है like 'Disk quota' and like 'DTI-Matt'

लेकिन, उत्पादन निदान हमेशा इतने सीधे नहीं होते हैं। कल्पना करें कि उन घटनाओं को खोजना आवश्यक है जहां डिस्क कोटा 125 एमबी से नीचे था?

सेरिलॉग के साथ, यह सबसे अधिक सिंक में संभव है जो एक प्रकार का उपयोग करता है:

Quota < 125

एक रेगुलर एक्सप्रेशन से क्वेरी इस तरह का निर्माण है संभव है, लेकिन यह अंतिम उपाय के एक उपाय किया जा रहा समाप्त होता है थकाऊ तेजी से हो जाता है और आम तौर पर।

अब इसमें एक घटना प्रकार जोड़ें:

Quota < 125 and EventType = 0x1234abcd

आप यहां यह देखना शुरू करते हैं कि कैसे इन क्षमताओं को सीधे-सीधे तरीके से संयोजित किया जाता है ताकि लॉग के साथ उत्पादन डिबगिंग एक प्रथम श्रेणी के विकास गतिविधि की तरह महसूस हो।

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


4
मुझे यह जवाब पसंद है। बहुत अच्छी तरह से लिखा गया है और किसी कारण से मैं समझा नहीं सकता, मुझे मेरी सीट के किनारे पर रखता है।
जोक

16

जब आप प्रसंस्करण के लिए लॉग एकत्र कर रहे हों, तो इसे कुछ डेटाबेस में पार्स करने के लिए और / या बाद में संसाधित लॉग के माध्यम से खोज करने के लिए, संरचित लॉगिंग का उपयोग करके प्रसंस्करण को कुछ आसान / अधिक कुशल बनाता है। पार्सर ज्ञात संरचना ( जैसे JSON, XML, ASN.1, जो कुछ भी) का लाभ उठा सकते हैं और पार्सिंग के लिए राज्य मशीनों का उपयोग कर सकते हैं, नियमित अभिव्यक्तियों के विपरीत (जो कि संकलन और निष्पादित करने के लिए कम्प्यूटेशनल रूप से महंगी (अपेक्षाकृत) हो सकती है)। अपने सहकर्मी द्वारा सुझाए गए फ़्री-फ़ॉर्म टेक्स्ट की पार्सिंग, नियमित अभिव्यक्तियों पर भरोसा करने और उस पाठ को न बदलने के लिए निर्भर करती है । यह पार्सिंग को मुक्त-स्वरूप पाठ बना सकता है, बल्कि नाजुक ( यानी पार्सिंग कसकर कोड में सटीक पाठ के लिए युग्मित है)।

खोज / खोज मामले पर भी विचार करें, उदाहरण के लिए :

SELECT text FROM logs WHERE text LIKE "Disk quota";

LIKEशर्तों को हर textपंक्ति मूल्य के साथ तुलना की आवश्यकता होती है ; फिर, यह अपेक्षाकृत कम्प्यूटेशनल रूप से महंगा है, खासकर जब वाइल्डकार्ड का उपयोग किया जाता है:

SELECT text FROM logs WHERE text LIKE "Disk %";

संरचित लॉगिंग के साथ, आपकी डिस्क-त्रुटि संबंधित लॉग संदेश JSON में इस तरह दिख सकती है:

{ "level": "DEBUG", "user": "username", "error_type": "disk", "text": "Disk quota ... exceeded by user ..." }

इस तरह की संरचना के क्षेत्र बहुत आसानी से उदाहरण के लिए SQL टेबल कॉलम नामों को मैप कर सकते हैं , जिसका मतलब है कि लुकअप अधिक विशिष्ट / बारीक हो सकता है:

SELECT user, text FROM logs WHERE error_type = "disk";

आप उन स्तंभों पर अनुक्रमणिका रख सकते हैं जिनके मान आप बार-बार खोजने / देखने की अपेक्षा करते हैं, जब तक आप LIKEउन स्तंभ मानों के लिए खंडों का उपयोग नहीं करते हैं । जितना अधिक आप अपने लॉग संदेश को विशिष्ट श्रेणियों में तोड़ सकते हैं, उतना ही अधिक लक्षित आप अपनी खोज कर सकते हैं। उदाहरण के लिए, error_typeऊपर दिए गए उदाहरण में फ़ील्ड / कॉलम के अलावा , आप "error_category": "disk", "error_type": "quota"समरूप या समरूप बना सकते हैं ।

अधिक संरचना अपनी लॉग संदेशों में आपके पास, (जैसे कि अधिक अपने पार्स / खोज प्रणाली fluentd, elasticsearch, kibana) है कि संरचना का लाभ लेने के लिए, और अधिक से अधिक गति और कम CPU / स्मृति के साथ अपने कार्य कर सकते हैं।

उम्मीद है की यह मदद करेगा!


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

1
+1 मुझसे भी, मुझे लगता है कि यह नाखून है। घटना के प्रकार के मामले में भी विस्तार करने के लिए, नीचे थोड़ा अलग सूत्रीकरण जोड़ा गया।
निकोलस ब्लुमहार्ट 3

8

जब आपका ऐप प्रतिदिन कुछ सौ लॉग संदेश बनाता है, तो आपको संरचित लॉगिंग से अधिक लाभ नहीं मिलेगा। आप निश्चित रूप से तब करेंगे जब आपके पास प्रति सेकंड कुछ सौ लॉग संदेश कई अलग-अलग तैनात किए गए ऐप से आएंगे।

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

मैंने SQL select .. likeऔर regexps के साथ "बेसिक लॉगिंग और सर्चिंग" के सेटअप को देखा है, जहां इसकी सीमा समाप्त हो जाती है - झूठे पॉज़िटिव्स, चूक, नॉरवॉन बग्स के साथ भयानक फ़िल्टर कोड हैं जिन्हें बनाए रखना मुश्किल है और कोई भी स्पर्श नहीं करना चाहता है। नए लॉग संदेश जो फ़िल्टर की मान्यताओं का पालन नहीं करते हैं, कोड लेन में लॉगिंग स्टेटमेंट को छूने के लिए अनिच्छा वे रिपोर्ट को तोड़ते हैं, आदि।

इस समस्या से बेहतर तरीके से निपटने के लिए कई सॉफ्टवेयर पैकेज उभर रहे हैं। सीरिलॉग है, मैंने सुना है कि एनएलओजी टीम इसे देख रही है , और हमने StructuredLogging.Jsonनॉल्ग के लिए लिखा है , मैं यह भी देखता हूं कि नए एएसपी.नेट कोर लॉगिंग एब्रीशिएंट्स "लॉगिंग प्रदाताओं को लागू करने के लिए संभव बनाते हैं ... संरचित लॉगिंग"।

स्ट्रक्चर्डलॉगिंग के साथ एक उदाहरण। आप इस तरह एक NLog लकड़हारा के लिए लॉग इन करें:

logger.ExtendedError("Order send failed", new { OrderId = 1234, RestaurantId = 4567 } );

यह संरचित डेटा किबना जाता है। मान लॉग प्रविष्टि 1234के OrderIdक्षेत्र में संग्रहीत किया जाता है । फिर आप उदाहरण के लिए किबाना क्वेरी सिंटैक्स का उपयोग करके खोज कर सकते हैं जहाँ सभी लॉग प्रविष्टियाँ हैं @LogType:nlog AND Level:Error AND OrderId:1234

Messageऔर OrderIdअब सिर्फ ऐसे क्षेत्र हैं जिन्हें सटीक या अनुभवहीन मैचों के लिए खोजा जा सकता है, जैसा कि आप की जरूरत है, या मायने रखता है। यह शक्तिशाली और लचीला है।

से StructuredLogging सर्वोत्तम प्रथाओं :

लॉग किया गया संदेश हर बार एक जैसा होना चाहिए। यह एक निरंतर स्ट्रिंग होना चाहिए, न कि डेटा मान जैसे कि आईडी या मात्रा को सम्‍मिलित करने के लिए एक स्ट्रिंग। फिर खोजना आसान है।

लॉग किया गया संदेश अलग होना चाहिए अर्थात असंबंधित लॉग स्टेटमेंट द्वारा निर्मित संदेश जैसा नहीं होना चाहिए। फिर इसकी खोज असंबंधित चीजों से भी मेल नहीं खाती।

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