लकड़हारा वर्ग प्रति लकड़हारा उपयोग करने की सलाह क्यों देता है?


88

NLog के दस्तावेज के अनुसार:

अधिकांश एप्लिकेशन प्रति वर्ग एक लकड़हारे का उपयोग करेंगे, जहां लकड़हारा का नाम कक्षा के नाम के समान है।

यह वही तरीका है जो log4net संचालित करता है। यह एक अच्छा अभ्यास क्यों है?


1
हम्म। ऐसा लगता है कि यहां दो मुद्दे हैं - एक प्रति कक्षा में एक वास्तविक लॉग ऑब्जेक्ट है, और एक का नाम है जो कक्षा के समान है।
पीटर रेकोर

जवाबों:


59

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

निम्नलिखित की तुलना करें:

प्रति वर्ग लॉग इन करें

using System.Reflection;
private static readonly ILog _logger = 
    LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);    

public void SomeMethod()
{
    _logger.DebugFormat("File not found: {0}", _filename);
}

एप्लिकेशन (या समान) के प्रति एक लकड़हारा

Logger.DebugFormat("File not found: {0}", _filename); // Logger determines caller

-- or --

Logger.DebugFormat(this, "File not found: {0}", _filename); // Pass in the caller

दूसरे उदाहरण का उपयोग करते हुए, लकड़हारे को यह देखने के लिए स्टैक ट्रेस बनाने की आवश्यकता होगी कि कौन उसे बुला रहा था या आपके कोड को हमेशा कॉलर में पास करना होगा। लकड़हारा-प्रति-वर्ग शैली के साथ, आप अभी भी ऐसा करते हैं, लेकिन आप इसे प्रति कॉल के बजाय एक बार प्रति कक्षा में कर सकते हैं और एक गंभीर प्रदर्शन समस्या को समाप्त कर सकते हैं।


धन्यवाद, जो चीजों को स्पष्ट करने में मदद करता है। हम केवल मैन्युअल रूप से संदेश में कक्षा का नाम और विधि डाल रहे थे (यानी "ImageCreator.CreateThumbnail ()" कहा जाता है), लेकिन यह बेहतर है अगर लकड़हारा इसे संभाल सकता है।
डेनियल टी।

1
सिर्फ FYI करें, इसका "बेहतर" अभ्यास हो सकता है, प्रति वर्ग (यानी स्थिर) के बजाय एक लॉगर प्रति उदाहरण है, क्योंकि इससे थ्रेड जानकारी जैसी जानकारी कैप्चर करना आसान हो जाता है। जाहिर है कि यह स्वाद की बात है, कोई "कठिन और तेज़ नियम" नहीं, लेकिन मैं बस इसे बाहर फेंकना चाहता था।
विल हार्टुंग

7
@ क्या आप समझा सकते हैं कि थोड़ा और? प्रति कक्षा एक लकड़हारा का उपयोग करते समय, मैं हमेशा थ्रेड आईडी लॉग करता हूं ताकि लकड़हारे को वर्तमान थ्रेड जानकारी मिल सके। कोई भी अन्य थ्रेड जानकारी लकड़हारे के लिए भी उपलब्ध होगी।
जेरेमी विएबे

@ जेरेमी वाइबे: क्या यह एकमात्र कारण है? कार्यात्मक रूप से कोई समस्या नहीं है अगर मैं पूरे ऐप के लिए टाइप लकड़हारे के एकल वैश्विक चर का उपयोग करता हूं?
जियोर्जिम

1
@Giorgi नहीं, मुझे ऐसा नहीं लगता। आप इन सूचनाओं को इन दिनों CallerInformation विशेषताओं के साथ प्राप्त कर सकते हैं, जो प्रति वर्ग एक लकड़हारे को
जेरेमी

15

NLog में "प्रति फ़ाइल लकड़हारा" का उपयोग करने के लिए लाभ: आपको नामस्थान और वर्ग नाम से लॉग्स को प्रबंधित / फ़िल्टर करने की संभावना है। उदाहरण:

<logger name="A.NameSpace.MyClass"      minlevel="Debug" writeTo="ImportantLogs" /> 
<logger name="A.NameSpace.MyOtherClass" minlevel="Trace" writeTo="ImportantLogs" /> 
<logger name="StupidLibrary.*"          minlevel="Error" writeTo="StupidLibraryLogs" />

<!-- Hide other messages from StupidLibrary -->
<logger name="StupidLibrary.*" final="true" /> 

<!-- Log all but hidden messages -->
<logger name="*" writeTo="AllLogs" /> 

ऐसा करने के लिए NLogger के पास बहुत उपयोगी कोड स्निपेट है। nloggerटुकड़ा निम्नलिखित कोड का निर्माण करेगा:

private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

तो केवल कुछ कीस्ट्रोक्स और आपके पास प्रति वर्ग लकड़हारा है। यह लकड़हारे के नाम के रूप में नाम स्थान और वर्ग नाम का उपयोग करेगा। अपने वर्ग लकड़हारे को अलग नाम सेट करने के लिए, आप इसका उपयोग कर सकते हैं:

private static NLog.Logger logger = NLog.LogManager.GetLogger("MyLib.MyName");

और, जैसा कि @JeremyWiebe ने कहा, आपको उस वर्ग का नाम प्राप्त करने के लिए ट्रिक्स का उपयोग करने की आवश्यकता नहीं है जो एक संदेश को लॉग करने की कोशिश कर रहा है: लकड़हारा का नाम (जो आमतौर पर वर्ग का नाम होता है) को फाइल करने में आसान हो सकता है (या अन्य लक्ष्य) ${logger}लेआउट में उपयोग करके ।


5

मैं इस पसंद के लिए कुछ कारण देख सकता हूं।

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

4

NLog के मामले में एक प्रदर्शन लाभ भी है। अधिकांश उपयोगकर्ता उपयोग करेंगे

Logger logger = LogManager.GetCurrentClassLogger()

स्टैक ट्रेस से वर्तमान वर्ग को देखते हुए कुछ (लेकिन ज्यादा नहीं) प्रदर्शन करें।


3

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

एक अच्छा उदाहरण जहां यह सबसे अच्छा तरीका नहीं है, हाइबरनेट का SQL लॉग है। एक साझा लकड़हारा है जिसका नाम "Hibernate.SQL" या ऐसा ही कुछ है, जहाँ कई अलग-अलग वर्ग एक एकल लकड़हारा वर्ग के लिए कच्चा SQL लिखते हैं।


2

यदि आप हर बार एक लकड़हारा वस्तु बनाने की जरूरत नहीं है, तो विकास के दृष्टिकोण से, यह सबसे आसान है। दूसरी ओर, यदि आप नहीं करते हैं, बल्कि आप इसे गतिशील रूप से प्रतिबिंब का उपयोग करके बनाते हैं, तो यह प्रदर्शन को धीमा कर देगा। इसे हल करने के लिए, आप निम्न कोड का उपयोग कर सकते हैं जो लकड़हारे को गतिशील रूप से अतुल्यकालिक बनाता है:

using NLog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WinForms
{
    class log
    {

        public static async void Log(int severity, string message)
        {
            await Task.Run(() => LogIt(severity, message));
        }

        private static void LogIt(int severity, string message)
        {
            StackTrace st = new StackTrace();
            StackFrame x = st.GetFrame(2);     //the third one goes back to the original caller
            Type t = x.GetMethod().DeclaringType;
            Logger theLogger = LogManager.GetLogger(t.FullName);

            //https://github.com/NLog/NLog/wiki/Log-levels
            string[] levels = { "Off", "Trace", "Debug", "Info", "Warn", "Error", "Fatal" };
            int level = Math.Min(levels.Length, severity);
            theLogger.Log(LogLevel.FromOrdinal(level), message);

        }
    }
}

1

दो कारणों से तुरंत वसंत:

  1. प्रत्येक वर्ग के लिए एक अलग लॉग होने से किसी दिए गए वर्ग से संबंधित सभी लॉग संदेश / त्रुटियों को एक साथ समूह में रखना आसान हो जाता है।
  2. एक वर्ग के भीतर एक लॉग होने से आप आंतरिक विवरणों को लॉग इन कर सकते हैं, जो कक्षा के बाहर सुलभ नहीं हो सकता है (उदाहरण के लिए, निजी राज्य, किसी वर्ग के कार्यान्वयन से संबंधित जानकारी आदि)।

2
यदि कक्षा स्तर पर या विश्व स्तर पर इसे परिभाषित किया जाए तो आपके पास कक्षा में कोई लकड़हारा है। ग्लोबल लॉगर दृश्यता के दृष्टिकोण से वर्ग "बाहर" नहीं हैं। आप अभी भी कक्षा के भीतर से वैश्विक लकड़हारे को संदर्भित कर रहे हैं, ताकि आपके पास पूर्ण दृश्यता हो।
रॉबर्ट

0

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


1
यह उस वर्ग को किसी अन्य एप्लिकेशन में उपयोग करना कठिन बनाता है। आपको लॉगिंग लाइब्रेरी का संदर्भ देना होगा कि आपको यह पसंद है या नहीं।
पियोट्र पर्क

0

नेमस्पेस या वर्ग द्वारा एपेंडर्स को कॉन्फ़िगर करना आसान बनाता है।


0

यदि आप एनएलओजी का उपयोग कर रहे हैं, तो आप कॉल को कॉन्फ़िगर में निर्दिष्ट कर सकते हैं, यह वर्ग नाम और विधि रिकॉर्ड करेगा जहां लॉगिंग स्टेटमेंट स्थित था।

<property name="CallSite" value="${callsite}" />

फिर आप अपने लकड़हारे के नाम या असेंबली के नाम के लिए एक स्थिरांक का उपयोग कर सकते हैं।

अस्वीकरण: मुझे नहीं पता कि एनएलओजी इस जानकारी को कैसे एकत्र करता है, मेरा अनुमान प्रतिबिंब होगा, इसलिए आपको प्रदर्शन पर विचार करने की आवश्यकता हो सकती है। यदि आप NLOG v4.4 या बाद के संस्करण का उपयोग नहीं कर रहे हैं, तो Async विधियों के साथ कुछ समस्याएँ हैं।

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