एक डिजाइन के नजरिए से, लॉगिंग के लिए सर्वोत्तम अभ्यास क्या हैं? [बन्द है]


11

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

लेकिन ऑब्जेक्ट-ओरिएंटेड भाषा में डिज़ाइन के दृष्टिकोण से, लॉगिंग के लिए सर्वोत्तम अभ्यास क्या हैं जो ओओपी और पैटर्न का पालन करते हैं?

नोट: मैं वर्तमान में C # में ऐसा कर रहा हूं, इसलिए C # में उदाहरण स्पष्ट रूप से स्वागत योग्य हैं। मैं जावा और रूबी में भी उदाहरण देखना चाहूंगा।


संपादित करें: मैं log4net का उपयोग कर रहा हूं। मैं अभी नहीं जानता कि इसमें प्लग करने का सबसे अच्छा तरीका क्या है।

जवाबों:


6

सबसे अच्छा अभ्यास जो मैं सुझाऊंगा, वह यह है कि आप को रोल करने के बजाय log4j का उपयोग करें। (जिसे जावा से C # और रूबी दोनों में पोर्ट किया गया है, इसलिए यह उन सभी 3 भाषाओं पर लागू होता है जिनमें आपकी रुचि है।)

यदि आप उस मैनुअल पेज के माध्यम से पढ़ते हैं तो आपको कई अन्य सर्वोत्तम प्रथाओं की खोज होगी। जैसे कि आपके आवेदन के बाहर हल्के, विन्यास योग्य होना, स्वतंत्र रूप से आपके आवेदन के विभिन्न भागों के लिए लॉगिंग को ऊपर और नीचे करना, और इसी तरह।


5

जहाँ मैं काम करता हूँ हम बहुत सारे .NET डेस्कटॉप ऐप लिखते हैं। हम आम तौर पर अपने घटकों में 2 घटनाओं को लागू करते हैं, एक लॉगिंग जानकारी के लिए और दूसरा लॉगिंग अपवादों के लिए (हालांकि हम अक्सर अलग-अलग घटना को बढ़ाने के बजाय अपवादों को बुदबुदाते हैं। यह स्थिति पर निर्भर करता है)। इस वास्तुकला का उपयोग करते हुए, हमारे पुस्तकालयों में से किसी को भी यह जानने की आवश्यकता नहीं है कि लॉगिंग कैसे लागू की जाती है या जानकारी का उपयोग, संग्रहित या उपचार कैसे किया जाता है। फिर हमारे पास एप्लिकेशन को लॉगिंग ईवेंट को इस तरीके से हैंडल करना है जो उस ऐप के लिए उपयुक्त है। कई साल पहले इस वास्तुकला ने एमएस एंटरप्राइज लाइब्रेरी का उपयोग करने से बिटफ़ैक्ट्री के लॉगिंग घटक को एक बहुत ही सरल संक्रमण के लिए हमारा स्विच बनाया।


इवेंट / ऑब्जर्वर पैटर्न का उपयोग करने के लिए +1: प्रेक्षक को बदल दें, आपने लॉगिंग बदल दी है
Matthieu M.

2

चूँकि आप C # में ऐसा कर रहे हैं, मैं आपको NLog और ElMAH को देखने की सलाह दूंगा। वे बहुत आसानी से NUGET का उपयोग कर स्थापित किया जा सकता है। मैंने नीचे कुछ लिंक दिए हैं ताकि आप अधिक जानकारी प्राप्त कर सकें।


2

व्यक्तिगत रूप से, मैं पसंद की लॉगिंग रूपरेखा (मेरे मामले में, एंटलिब क्योंकि मैं .NET के साथ काम करता हूं) लेता हूं और लॉगिंग के लिए AOP पहलू लिखता हूं।

फिर आप किसी भी तरीके / गुण / वर्गों / नामस्थानों को चिह्नित कर सकते हैं और स्रोत को अव्यवस्थित किए बिना उनमें लॉगिंग जोड़ सकते हैं।


यह बहुत दिलचस्प लगता है, लेकिन मेरे पास इस बारे में आरक्षण है कि आप क्या लॉग कर पाएंगे और लॉग कितना सूचनात्मक होगा (यानी "सिर्फ" इंस्ट्रूमेंटेशन ऑफ मेथड्स)। इस दृष्टिकोण का एक कार्यशील उदाहरण देखना पसंद करेंगे कि क्या किया जा सकता है और क्या नहीं। खासकर जब मैं एक नए ऐप पर शुरुआत कर रहा हूं और यह देखना चाहता हूं कि मैं इसे कहां तक ​​ले जा सकता हूं।
मार्जन वेनेमा

@marjan Venema: पोस्ट शार्प डॉक्यूमेंटेशन में एक पहलू का एक उदाहरण है जो एक विधि में प्रवेश / बाहर निकलता है। doc.sharpcrafters.com/postsharp/2.0/##PostSharp.chm/html/… पोस्ट शार्प के मामले में, यह समय पर स्रोत में विशेषता से कोड को बुनता है , इसलिए यह कुछ अन्य लोगों की तरह प्रदर्शन नहीं करता है।
स्टीवन एवर्स

1

वर्तमान में मैं जिस सिस्टम पर काम कर रहा हूं, वह एक इवेंट संचालित आर्किटेक्चर और मैसेजिंग का उपयोग करता है, ताकि हमारी प्रणाली में अधिकांश क्रियाएं एक कमांड का परिणाम हो और वे घटनाओं (डीटीओ कक्षाओं के रूप में जो एक मानक प्रतिनिधि घटना के बजाय भेजे जाते हैं) के परिणामस्वरूप होती हैं। हम ईवेंट हैंडलर संलग्न करते हैं जिसका एकमात्र उद्देश्य लॉगिंग को संभालना है। यह डिज़ाइन हमें स्वयं को दोहराने में मदद नहीं करता है, और कार्यक्षमता को जोड़ने / बदलने के लिए मौजूदा कोड को संशोधित करने की भी आवश्यकता नहीं है।

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

मैं जरूरी नहीं कहूंगा कि यह सबसे अच्छा अभ्यास है, जैसा कि मुझे लगता है कि मैं क्या और कैसे अक्सर लॉग ऑन करने के लिए अपना मन बदल रहा हूं - और हर बार जब मुझे एक समस्या का निदान करने के लिए लॉग का उपयोग करने की आवश्यकता होती है, तो मैं अनिवार्य रूप से सुधार करने के तरीके ढूंढता हूं। जानकारी मैं रिकॉर्ड।

हालांकि, मैं कहूंगा कि प्रासंगिक जानकारी दर्ज करना (विशेष रूप से एक Ctrl-F / खोजा तरीका) सबसे महत्वपूर्ण हिस्सा है।

दूसरा सबसे महत्वपूर्ण हिस्सा अपने मुख्य तर्क से दूर लॉगिंग कोड हो रही है - यह एक विधि बदसूरत और लंबी और घुमावदार कर सकते हैं बहुत जल्दी।

public class MctLogger :
    IEventHandler<StoryImported>,
    IEventHandler<StoryScanned>,
    IEventHandler<SourceDirectoryMissing>,
    IEventHandler<SourceDirectoryAccessError>,
    IEventHandler<CannotCreateScannedStoryDirectory>,
    IEventHandler<CannotReadStoryDocument>,
    IEventHandler<StorySkippedPastCutoff>,
    IEventHandler<StorySkippedDuplicateUniqueId>,
    IEventHandler<StorySkippedByFilter>
{

    public void Observe(StoryImported e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StoryImported");
        log.Info("Story Unique ID: {Story.UniqueId}, Content ID: {ContentId}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(StoryScanned e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StoryScanned");
        log.Info("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(SourceDirectoryMissing e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.SourceDirectoryMissing");
        log.Error("Directory: " + e.Directory);
    }

    public void Observe(SourceDirectoryAccessError e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.SourceDirectoryAccessError");
        log.Error(e.Exception, "Exception: " + e.Exception.Message);
    }

    public void Observe(CannotCreateScannedStoryDirectory e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.CannotCreateScannedStoryDirectory");
        log.Error(e.Exception, "Directory: {Directory}, Exception: {Exception.Message}".SmartFormat(e));
    }

    public void Observe(CannotReadStoryDocument e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.CannotReadStoryDocument");
        if (e.Exception == null) {
            log.Warn("File: {FilePath}".SmartFormat(e));
        }
        else {
            log.Warn(e.Exception, "File: {FilePath}, Exception: {Exception.Message}".SmartFormat(e));
        }
    }

    public void Observe(StorySkippedPastCutoff e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedPastCutoff");
        log.Warn("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(StorySkippedDuplicateUniqueId e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedDuplicateUniqueId");
        log.Warn("Story Unique ID: {Story.UniqueId}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }

    public void Observe(StorySkippedByFilter e)
    {
        var log = Slf.LoggerService.GetLogger("RoboChef.Content.Mct.StorySkippedByFilter");
        log.Warn("Story Unique ID: {Story.UniqueId}, Reason: {Reason}, File: {FilePath}, Title: {Story.Headline}".SmartFormat(e));
    }
}

1

के रूप में अन्य लोगों ने कहा, उपयोग log4jया log4netया कुछ अन्य अच्छी तरह से बनाया प्रवेश ढांचा।

मैं वास्तव में व्यापार तर्क के रास्ते में लॉगिंग कोड को नापसंद करता हूं। इसलिए मैं उपयोग करता हूं Log4PostSharp। इसका मतलब है कि मैं इस तरह से तरीकों को एनोटेट करने के लिए पहलू ओरिएंटेड प्रोग्रामिंग का उपयोग कर सकता हूं :

[Log(LogLevel.Info, "Counting characters.")]
int CountCharacters(string arg) 
{
    return arg.Length;
}

या इस तरह एक विधानसभा में हर विधि:

[assembly: Log(AttributeTargetTypes = "*", 
 EntryLevel = LogLevel.Debug, ExitLevel = LogLevel.Debug, 
 ExceptionLevel = LogLevel.Error)]

0

मुझे यकीन नहीं है कि कोई ढांचा ऐसा करता है, लेकिन एक डिजाइन के नजरिए से, मैं जानकारी को मुख्य रूप से तीन श्रेणियों में लॉग इन करने की आवश्यकता होगी।

  1. विधि स्तर अनुरेखण
  2. अपवाद लॉगिंग
  3. अतिरिक्त रन-टाइम जानकारी डेवलपर्स का मानना ​​है कि रन-टाइम विफलता (या केवल रन-टाइम से संबंधित किसी भी व्यवहार) के मामले में जांच के लिए महत्वपूर्ण है।

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

Trace YourNamespace.* [public methods|constructors]
{  # options
   ignore trivial methods,
   format: "{time stamp}: {method name}({parameter list})",
   condition: "{Context.Instance.UserID in (12432,23432)}",
}

Exception YourNamespace.Program.Main [unhandled exceptions]
{
  format: "{time stamp}: {Context.Instance.UserId} {exception}",
  action: die,  # options are throw, swallow,
}

तीसरी श्रेणी के लिए, प्रोग्रामर सिर्फ एक या अधिक समर्पित "लॉगिंग" तरीके बना सकते हैं और पहली श्रेणी के लिए ट्रेसिंग का लाभ उठा सकते हैं। लॉगिंग विधियां एक स्टब बिंदु की सेवा करने से ज्यादा कुछ नहीं करती हैं, जिसमें अनुरेखण नियम लागू किए जा सकते हैं।

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