2010-12-15 22 views
6

मैं मौजूदा लॉगिंग संदेशों पर सभी संदेशों को श्रेणी उपसर्ग जोड़ना चाहता हूं। हालांकि, इस उपसर्ग को सभी मौजूदा लॉगिंग संदेशों में एक-एक करके जोड़ना कठिन है। क्या कोई तरीका है कि मैं कक्षा स्तर में केवल एक विशेषता जोड़ सकता हूं तो इस वर्ग के सभी संदेशों को कुछ श्रेणी के लिए लॉग किया जाएगा?log4net संदेश में श्रेणी उपसर्ग कैसे जोड़ें?

इसके बजाय जिस तरह से अभी नीचे के रूप में की

,

Log.Info("[Ref] Level 1 Starts ..."); 

मैं वास्तव में कुछ इस तरह या log4net.ILog परिभाषित करने के लिए एक अलग तरह से करना चाहते हैं।

[LoggingCategory("Ref")] 
public class MyClass 
{ 
    public void MyMethod() 
    { 
     Log.Info("Level 1 Starts ..."); 
    } 
} 
+1

इस सुविधा के लिए लॉगर्स पदानुक्रम का उपयोग कर लॉग 4नेट –

+0

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

+0

मैं यहां हासिल करने की कोशिश कर रहा हूं कि कुछ कक्षाओं के लिए लॉग फ़ाइलों को पार्स करना आसान हो। उदाहरण के लिए, यदि कक्षा ए और कक्षा बी संबंधित हैं और मैं मुख्य लॉग फ़ाइल से संबंधित सभी पंक्तियों से संबंधित श्रेणी ए और बी प्राप्त करना चाहता हूं। मेरा अनुभव आमतौर पर पाया जाता है कि यह मेरे लिए बहुत उपयोगी था। – tonyjy

उत्तर

4

दिलचस्प समस्या, किसी न किसी तरह का प्रयास ...

Log4NetLogger - प्रवेश एडाप्टर

public class Log4NetLogger 
{ 
    private readonly ILog _logger; 
    private readonly string _category; 

    public Log4NetLogger(Type type) 
    { 
     _logger = LogManager.GetLogger(type); 
     _category = GetCategory(); 
    } 

    private string GetCategory() 
    { 
     var attributes = new StackFrame(2).GetMethod().DeclaringType.GetCustomAttributes(typeof(LoggingCategoryAttribute), false); 
     if (attributes.Length == 1) 
     { 
      var attr = (LoggingCategoryAttribute)attributes[0]; 
      return attr.Category; 
     } 
     return string.Empty; 
    } 

    public void Debug(string message) 
    { 
     if(_logger.IsDebugEnabled) _logger.Debug(string.Format("[{0}] {1}", _category, message)); 
    } 
} 

LoggingCategoryAttribute - वर्गों के लिए लागू

[AttributeUsage(AttributeTargets.Class)] 
public class LoggingCategoryAttribute : Attribute 
{ 
    private readonly string _category; 

    public LoggingCategoryAttribute(string category) 
    { 
     _category = category; 
    } 

    public string Category { get { return _category; } } 
} 

LogTester - एक परीक्षण कार्यान्वयन

[LoggingCategory("LT")] 
public class LogTester 
{ 
    private static readonly Log4NetLogger Logger = new Log4NetLogger(typeof(LogTester)); 

    public void Test() 
    { 
     Logger.Debug("This log message should have a prepended category"); 
    } 
} 
+0

यह बहुत अच्छा लग रहा है, लेकिन प्रत्येक लॉगिंग कॉल पर GetCategory को कॉल करना महंगा हो सकता है। – wageoghe

+0

क्या आप GetCategory को कन्स्ट्रक्टर में ले जा सकते हैं? फिर यह प्रत्येक लॉगिंग कॉल पर GetCategory पर कॉल से बच जाएगा। – tonyjy

+0

@tonyjy, @wageoghe - अच्छी पकड़, निर्माण समय पर एक बार GetCategory को कॉल करने के लिए कोड संशोधित किया गया। – Jonathan

7

आप एक विशेषता के माध्यम से ऐसा करने के लिए कह रहे हैं। @ जोनाथन का सुझाव ऐसा लगता है कि यह शायद ठीक काम करेगा, लेकिन आप log4net की अंतर्निहित क्षमताओं का उपयोग करके एक अच्छा पर्याप्त परिणाम प्राप्त करने में सक्षम हो सकते हैं।

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

आम तौर पर एक इस तरह classname के आधार पर लकड़हारा पुनः प्राप्त होगा:

public class Typical 
{ 
    private static readonly ILog logger = 
     LogManager.GetLogger 
      (System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 

    public void F() 
    { 
    logger.Info("this message will be tagged with the classname"); 
    } 
} 

यह पूरी तरह से इस तरह कोई भी नाम के आधार पर वालों को पुनः प्राप्त करने स्वीकार्य है:

public class A 
{ 
    private static readonly ILog logger = LogManager.GetLogger("REF"); 

    public void F() 
    { 
    logger.Info("this message will be tagged with REF"); 
    } 
} 

public class B 
{ 
    private static readonly ILog logger = LogManager.GetLogger("REF"); 

    public void F() 
    { 
    logger.Info("this message will be tagged with REF"); 
    } 
} 

public class C 
{ 
    private static readonly ILog logger = LogManager.GetLogger("UMP"); 

    public void F() 
    { 
    logger.Info("this message will be tagged with UMP"); 
    } 
} 

पूर्ववर्ती उदाहरण में , कक्षा ए और बी को एक ही "श्रेणी" में माना जाता है, इसलिए उन्होंने उसी नाम से लॉगर को पुनर्प्राप्त किया। कक्षा सी एक अलग श्रेणी में है, इसलिए इसे लॉगर को एक अलग नाम से पुनर्प्राप्त किया गया।

आप अपनी खुद की "श्रेणी" पदानुक्रम के साथ अपने वालों (कॉन्फ़िग फ़ाइल में) कॉन्फ़िगर कर सकते हैं:

App 
App.DataAccess 
App.DataAccess.Create 
App.DataAccess.Read 
App.DataAccess.Update 
App.DataAccess.Delete 
App.UI 
App.UI.Login 
App.UI.Query 
App.UI.Options 

तुम भी पूरी तरह से योग्य लकड़हारा नाम का ही हिस्सा लॉग इन करने की लॉगर आउटपुट प्रारूप कॉन्फ़िगर कर सकते हैं। इस तरह कुछ:

%logger:2 

पूरी तरह से योग्य नाम के अंतिम 2 भाग प्राप्त करने के लिए।उदाहरण के लिए, यदि आपका वर्ग की पूरी तरह से योग्य नाम है:

NameSpaceA.NameSpaceB.NameSpaceC.Class 

फिर ऊपर प्रारूप होगा उत्पादन इस लकड़हारा नाम के रूप में:

NameSpaceC.Class 

मैं कर रहा हूँ 100% सिंटैक्स के बारे में निश्चित नहीं है क्योंकि मैं हेवन ' टी ने इसका इस्तेमाल नहीं किया और मुझे अभी एक अच्छा उदाहरण नहीं मिल रहा है।

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

शायद यह नाम स्थान पदानुक्रम के भीतर से एक भी नाम स्थान लॉग इन करने के लिए उपयोगी होगा:

हो सकता है कि आप अपने अपने नाम स्थान के आधार पर कक्षाओं "वर्गीकृत" कर सकते हैं। तो, हो सकता है कि आप कक्षा के तत्काल अभिभावक नामस्थान को अपनी श्रेणी के रूप में लॉग इन करना चाहें।

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

मुझे यकीन नहीं है कि आप लॉग 4नेट के साथ बॉक्स से बाहर कर सकते हैं, लेकिन आप लॉगर नाम प्राप्त करने और कक्षा के नाम और किसी भी "उच्च स्तर" नामस्थान को बंद करने के लिए आसानी से एक पैटर्न लयआउट कनवर्टर लिख सकते हैं।

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

Custom log4net property PatternLayoutConverter (with index)

फिर, यह पूरी तरह से योग्य वर्ग के नाम दिए गए:

NameSpaceA.NameSpaceB.NameSpaceC.Class 

आप पर विचार तत्काल माता पिता नाम स्थान "श्रेणी" हो सकता है। आप एक कस्टम PatternLayoutConverter, category परिभाषित है, और यह एक पैरामीटर ले लिया है, तो आपके विन्यास इस प्रकार दिखाई देंगे:

%category 

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

PatternLayoutConverter कुछ इस तरह (untested) दिख सकता है:

class CategoryLookupPatternConverter : PatternLayoutConverter 
    { 
    protected override void Convert(System.IO.TextWriter writer, LoggingEvent loggingEvent) 
    { 
     //Assumes logger name is fully qualified classname. Need smarter code to handle 
     //arbitrary logger names. 
     string [] names = loggingEvent.LoggerName.Split('.'); 
     string cat = names[names.Length - 1]; 
     writer.Write(setting); 
    } 
    } 

या, विकल्प संपत्ति का उपयोग कर वां नाम स्थान का नाम (अंत के सापेक्ष) प्राप्त करने के लिए:

class CategoryLookupPatternConverter : PatternLayoutConverter 
    { 
    protected override void Convert(System.IO.TextWriter writer, LoggingEvent loggingEvent) 
    { 
     //Assumes logger name is fully qualified classname. Need smarter code to handle 
     //arbitrary logger names. 
     string [] names = loggingEvent.LoggerName.Split('.'); 
     string cat; 
     if (Option > 0 && Option < names.Length) 
     { 
     cat = names[names.Length - Option]; 
     } 
     else 
     { 
     string cat = names[names.Length - 1]; 
     } 
     writer.Write(setting); 
    } 

    } 

विचार @ जोनाथन से बहुत अच्छा है, लेकिन यह एक नया लॉगर रैपर परिभाषित करने और बनाए रखने के लिए आपके हिस्से पर कुछ अतिरिक्त कोडिंग जोड़ता है (लेकिन बहुत से लोग ऐसा करते हैं और इसे विशेष रूप से भारी बोझ नहीं पाते हैं)। बेशक, मेरे कस्टम पैटर्न LayoutConverter विचारों को भी आपके हिस्से पर कस्टम कोड की आवश्यकता है।

एक अन्य दोष यह है कि GetCategory ऐसा लगता है कि प्रत्येक लॉगिंग कॉल पर कॉल करना बहुत महंगा हो सकता है।

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