2009-11-17 20 views
11

मैं कई अलग-अलग परियोजनाओं (शैल, मॉड्यूल, आदि) के साथ एक समग्र WPF (प्रिज्म) ऐप बना रहा हूं। मैं Log4Net का उपयोग कर लॉगिंग को लागू करने के लिए तैयार हो रहा हूं। ऐसा लगता है कि लॉगिंग सेट करने के दो तरीके हैं:समग्र ऐप के लिए सर्वश्रेष्ठ लॉगिंग दृष्टिकोण?

  • शैल प्रोजेक्ट सभी वास्तविक लॉगिंग करने दें। यह Log4Net का संदर्भ प्राप्त करता है, और अन्य परियोजनाओं को समग्र समग्र घटनाओं को आग लगने के लिए पता चलता है कि उसे कुछ लॉग करने की आवश्यकता है। वे प्रोजेक्ट केवल उन स्तरों के लिए ईवेंट को आग लगाते हैं जहां शैल की app.config फ़ाइल (DEBUG, ERROR, आदि) में लॉगिंग चालू होती है, ताकि प्रदर्शन को कम न किया जा सके।

  • मॉड्यूल, एक लॉग 4नेट संदर्भ सहित प्रत्येक प्रोजेक्ट दें, और लॉगिंग के लिए शैल को संदेश भेजने के बजाय प्रोजेक्ट को एक सामान्य लॉग फ़ाइल में लॉगिंग करने दें।

बेहतर तरीका कौन सा है? या, क्या कोई और दृष्टिकोण है जिस पर मुझे विचार करना चाहिए? आपकी सहायता के लिए धन्यवाद.

उत्तर

15

प्रिज्म में लॉग इन करने का सबसे आसान तरीका संपत्ति बूटस्ट्रैपर में संपत्ति को ओवरराइड करना है। LoggerFacade को ओवरराइड करके, आप किसी भी कॉन्फ़िगरेशन के साथ किसी भी कॉन्फ़िगरेशन के साथ पास कर सकते हैं जब तक कि लॉगर ILoggerFacade इंटरफ़ेस लागू करता है।

मैंने पाया (मैं उद्यम पुस्तकालय लॉगिंग ब्लॉक का उपयोग कर रहा है, लेकिन log4net के लिए कुछ इसी तरह सीधे आगे होना चाहिए लागू करने) प्रवेश करने के लिए काफी अच्छी तरह से काम करने के लिए निम्नलिखित:

अपने शेल में एक Boostrapper बनाएँ:

-My Project 
    -Shell Module (add a reference to the Infrastructure project) 
    -Bootstrapper.cs 

अपने इंफ्रास्ट्रक्चर परियोजना में एक लॉगिंग एडाप्टर बनाएँ, अर्थात्:

-My Project 
    -Infrastructure Module 
    -Adapters 
     -Logging 
     -MyCustomLoggerAdapter.cs 
     -MyCustomLoggerAdapterExtendedAdapter.cs 
     -IFormalLogger.cs 

MyCustomLoggerAdapt er कक्षा बूटस्ट्रैपर में 'लॉगरफेकडे' प्रॉपर्टी को ओवरराइड करने के लिए उपयोग की जाएगी। इसमें एक डिफ़ॉल्ट contstructor होना चाहिए कि सब कुछ खबर।

नोट: बूटस्ट्रैपर में LoggerFacade प्रॉपर्टी को ओवरराइड करके, आप अपने स्वयं के आंतरिक संदेशों को लॉग इन करने के लिए प्रिज्म के लिए लॉगिंग मैकेनिसिम प्रदान कर रहे हैं।आप अपने लॉजर में अपने लॉजर का उपयोग कर सकते हैं, या आप लॉगर को अधिक पूर्ण रूप से फीचर्ड लॉगर के लिए बढ़ा सकते हैं। (देखें MyCustomLoggerAdapterExtendedAdapter/IFormalLogger)

public class MyCustomLoggerAdapter : ILoggerFacade 
{ 

    #region ILoggerFacade Members 

    /// <summary> 
    /// Logs an entry using the Enterprise Library logging. 
    /// For logging a Category.Exception type, it is preferred to use 
    /// the EnterpriseLibraryLoggerAdapter.Exception methods." 
    /// </summary> 
    public void Log(string message, Category category, Priority priority) 
    { 
     if(category == Category.Exception) 
     { 
      Exception(new Exception(message), ExceptionPolicies.Default); 
      return; 
     } 

     Logger.Write(message, category.ToString(), (int)priority); 
    } 

    #endregion 


    /// <summary> 
    /// Logs an entry using the Enterprise Library Logging. 
    /// </summary> 
    /// <param name="entry">the LogEntry object used to log the 
    /// entry with Enterprise Library.</param> 
    public void Log(LogEntry entry) 
    { 
     Logger.Write(entry); 
    } 

    // Other methods if needed, i.e., a default Exception logger. 
    public void Exception (Exception ex) { // do stuff } 
} 

MyCustomLoggerAdapterExtendedAdapterMyCustomLoggerAdapter से dervied जाता है और एक और अधिक पूर्ण लकड़हारा के लिए अतिरिक्त कंस्ट्रक्टर्स प्रदान कर सकते हैं।

public class MyCustomLoggerAdapterExtendedAdapter : MyCustomLoggerAdapter, IFormalLogger 
{ 

    private readonly ILoggingPolicySection _config; 
    private LogEntry _infoPolicy; 
    private LogEntry _debugPolicy; 
    private LogEntry _warnPolicy; 
    private LogEntry _errorPolicy; 

    private LogEntry InfoLog 
    { 
     get 
     { 
      if(_infoPolicy == null) 
      { 
       LogEntry log = GetLogEntryByPolicyName(LogPolicies.Info); 
       _infoPolicy = log; 
      } 
      return _infoPolicy; 
     } 
    } 

    // removed backing code for brevity 
    private LogEntry DebugLog... WarnLog... ErrorLog 


    // ILoggingPolicySection is passed via constructor injection in the bootstrapper 
    // and is used to configure various logging policies. 
    public MyCustomLoggerAdapterExtendedAdapter (ILoggingPolicySection loggingPolicySection) 
    { 
     _config = loggingPolicySection; 
    } 


    #region IFormalLogger Members 

    /// <summary> 
    /// Info: informational statements concerning program state, 
    /// representing program events or behavior tracking. 
    /// </summary> 
    /// <param name="message"></param> 
    public void Info(string message) 
    { 
     InfoLog.Message = message; 
     InfoLog.ExtendedProperties.Clear(); 
     base.Log(InfoLog); 
    } 

    /// <summary> 
    /// Debug: fine-grained statements concerning program state, 
    /// typically used for debugging. 
    /// </summary> 
    /// <param name="message"></param> 
    public void Debug(string message) 
    { 
     DebugLog.Message = message; 
     DebugLog.ExtendedProperties.Clear(); 
     base.Log(DebugLog); 
    } 

    /// <summary> 
    /// Warn: statements that describe potentially harmful 
    /// events or states in the program. 
    /// </summary> 
    /// <param name="message"></param> 
    public void Warn(string message) 
    { 
     WarnLog.Message = message; 
     WarnLog.ExtendedProperties.Clear(); 
     base.Log(WarnLog); 
    } 

    /// <summary> 
    /// Error: statements that describe non-fatal errors in the application; 
    /// sometimes used for handled exceptions. For more defined Exception 
    /// logging, use the Exception method in this class. 
    /// </summary> 
    /// <param name="message"></param> 
    public void Error(string message) 
    { 
     ErrorLog.Message = message; 
     ErrorLog.ExtendedProperties.Clear(); 
     base.Log(ErrorLog); 
    } 

    /// <summary> 
    /// Logs an Exception using the Default EntLib Exception policy 
    /// as defined in the Exceptions.config file. 
    /// </summary> 
    /// <param name="ex"></param> 
    public void Exception(Exception ex) 
    { 
     base.Exception(ex, ExceptionPolicies.Default); 
    } 

    #endregion 


    /// <summary> 
    /// Creates a LogEntry object based on the policy name as 
    /// defined in the logging config file. 
    /// </summary> 
    /// <param name="policyName">name of the policy to get.</param> 
    /// <returns>a new LogEntry object.</returns> 
    private LogEntry GetLogEntryByPolicyName(string policyName) 
    { 
     if(!_config.Policies.Contains(policyName)) 
     { 
      throw new ArgumentException(string.Format(
       "The policy '{0}' does not exist in the LoggingPoliciesCollection", 
       policyName)); 
     } 

     ILoggingPolicyElement policy = _config.Policies[policyName]; 

     var log = new LogEntry(); 
     log.Categories.Add(policy.Category); 
     log.Title = policy.Title; 
     log.EventId = policy.EventId; 
     log.Severity = policy.Severity; 
     log.Priority = (int)policy.Priority; 
     log.ExtendedProperties.Clear(); 

     return log; 
    } 

} 


public interface IFormalLogger 
{ 

    void Info(string message); 

    void Debug(string message); 

    void Warn(string message); 

    void Error(string message); 

    void Exception(Exception ex); 

} 

में Bootstrapper:

public class MyProjectBootstrapper : UnityBootstrapper 
{ 

    protected override void ConfigureContainer() 
    { 
    // ... arbitrary stuff 

    // create constructor injection for the MyCustomLoggerAdapterExtendedAdapter 
     var logPolicyConfigSection = ConfigurationManager.GetSection(LogPolicies.CorporateLoggingConfiguration); 
     var injectedLogPolicy = new InjectionConstructor(logPolicyConfigSection as LoggingPolicySection); 

     // register the MyCustomLoggerAdapterExtendedAdapter 
     Container.RegisterType<IFormalLogger, MyCustomLoggerAdapterExtendedAdapter>(
       new ContainerControlledLifetimeManager(), injectedLogPolicy); 

    } 

    private readonly MyCustomLoggerAdapter _logger = new MyCustomLoggerAdapter(); 
    protected override ILoggerFacade LoggerFacade 
    { 
     get 
     { 
      return _logger; 
     } 
    } 

} 

अंत में, या तो लकड़हारा उपयोग करने के लिए, तुम सब करने की जरूरत है उचित इंटरफ़ेस आपके क्लास 'निर्माता के लिए जोड़ रहा है और UnityContainer के लिए लकड़हारा इंजेक्षन जाएगा आप:

public partial class Shell : Window, IShellView 
{ 
    private readonly IFormalLogger _logger; 
    private readonly ILoggerFacade _loggerFacade; 

    public Shell(IFormalLogger logger, ILoggerFacade loggerFacade) 
    { 
     _logger = logger; 
     _loggerFacade = loggerFacade 

     _logger.Debug("Shell: Instantiating the .ctor."); 
     _loggerFacade.Log("My Message", Category.Debug, Priority.None); 

     InitializeComponent(); 
    } 


    #region IShellView Members 

    public void ShowView() 
    { 
     _logger.Debug("Shell: Showing the Shell (ShowView)."); 
     _loggerFacade.Log("Shell: Showing the Shell (ShowView).", Category.Debug, Priority.None); 
     this.Show(); 
    } 

    #endregion 

} 

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

कोडप्लेक्स पर कंपोजिट WPF contrib प्रोजेक्ट पर simple example of uisng Log4Net भी है।

HTH के

+0

मुझे इस समाधान में log4net की पदानुक्रमित लॉगिंग याद आ रही है। मुझे लगता है कि कुछ भी प्रिज्म में गायब है। –

0

प्रत्येक मॉड्यूल के लिए अलग लॉगर कॉन्फ़िगरेशन होने से तैनाती पर समस्याएं हो सकती हैं। याद रखें कि एक पावर उपयोगकर्ता या व्यवस्थापक पूरी तरह से आपके लॉगिंग के लक्ष्य को बदल सकता है, डेटाबेस पर रीडायरेक्ट कर सकता है या एक केंद्रीय भंडार समेकित लॉगिंग सेवा (जैसे my company एक)। यदि सभी अलग मॉड्यूल में अलग-अलग कॉन्फ़िगरेशन होते हैं, तो बिजली उपयोगकर्ता/व्यवस्थापक को प्रत्येक मॉड्यूल (प्रत्येक .config फ़ाइल में, या प्रत्येक मॉड्यूल के अनुभाग में मुख्य app.config में) के लिए कॉन्फ़िगरेशन दोहराना पड़ता है, और हर बार स्थान में परिवर्तन को दोहराएं/स्वरूपण होता है। और इसके अलावा, यह देखते हुए कि परिशिष्ट को कॉन्फ़िगरेशन से रन टाइम पर जोड़ा जाता है और ऐसे परिशिष्ट हो सकते हैं जिन्हें आप इस समय के बारे में कुछ भी नहीं जानते हैं, कोई ऐसे एपेंडर का उपयोग कर सकता है जो फ़ाइल को लॉक करता है और परिणामस्वरूप ऐप मॉड्यूल के बीच संघर्ष होता है। Hsving एक एकल log4.net विन्यास प्रशासन को सरल बनाता है।

व्यक्तिगत मॉड्यूल अभी भी प्रत्येक की जरूरतों के लिए कॉन्फ़िगर किया जा सकता है (उदाहरण के लिए डीबी परत के लिए जानकारी, यूआई परत के लिए त्रुटि)। प्रत्येक मॉड्यूल को अपने प्रकार के लिए पूछकर लॉगर मिल जाएगा: LogManager.GetLogger(typeof(MyModule); लेकिन केवल शैल लॉगर को कॉन्फ़िगर करेगा (उदाहरण के लिए कॉल XmlConfigurator.Configure), अपने स्वयं के app.config का उपयोग करके।

+1

भले ही प्रत्येक प्रोजेक्ट के पास Log4Net का अपना संदर्भ हो, फिर भी उनके पास अलग-अलग कॉन्फ़िगरेशन फ़ाइलें नहीं होंगी - जो अप्रबंधनीय होंगी। जहां समाधान में प्रत्येक प्रोजेक्ट अपने स्वयं के लॉगिंग करता है (अपने स्वयं के लॉग 4नेट संदर्भ के साथ) व्यावहारिक मुख्य ऐप में एक कॉन्फ़िगरेशन फ़ाइल का उपयोग करना प्रतीत होता है। Http://nirajrules.wordpress.com/2008/06/14/blogging-best-practicies/ –

+0

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

+0

मुझे अंततः मेरा जवाब मिल गया - नीचे देखें। मैं मेट्रो Smurf की प्रतिक्रिया से 'सही' जवाब बदलने वाला नहीं हूँ। वह प्रिज्म को Log4Net इंटरफेस करने का एक अच्छा उदाहरण देता है। लेकिन नीचे मेरी प्रतिक्रिया वास्तव में आपके द्वारा स्थापित लॉगर को प्राप्त करने के मूल मुद्दे को संबोधित करती है। –

3

मैं अंत में वापस इस एक पर पहुंचे, और यह पता चला है इस सवाल का जवाब वास्तव में बहुत सरल है। शैल प्रोजेक्ट में, Log4Net को कस्टम लॉगर के रूप में कॉन्फ़िगर करें। प्रिज्म डॉक्यूमेंटेशन (फरवरी 200 9) बताता है कि पी पर ऐसा कैसे करें। 287)। शैल प्रोजेक्ट एकमात्र ऐसा प्रोजेक्ट है जिसे Log4Net के संदर्भ की आवश्यकता है। लॉगर तक पहुंचने के लिए (मान लें कि सभी मॉड्यूल प्रिज्म आईओसी कंटेनर का संदर्भ पारित कर चुके हैं), आईओसी कंटेनर में केवल ILoggerFacade को हल करें, जो आपको अपने कस्टम लॉगर का संदर्भ देगा। इस लॉगर को सामान्य तरीके से एक संदेश पास करें।

तो, शैल को वापस आने की कोई आवश्यकता नहीं है, और लॉग 4 नेट संदर्भों के लिए मॉड्यूल की आवश्यकता नहीं है। पवित्र मैकेरल, मुझे आईओसी कंटेनर पसंद है!

+0

मुझे भी प्यार है! :) – Attilah

2

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

मेरा सुझाव है, क्यों न केवल मानक Debug/Trace पर भरोसा करें और अपने TraceListener को लागू करें। इस तरह यह प्रिज्म/गैर-प्रिज्म भागों दोनों के लिए अच्छा काम करेगा। आप इसके साथ लचीलापन के वांछित स्तर प्राप्त कर सकते हैं।

+0

आमेन। मैं एक ऐप पर काम कर रहा हूं जहां डेवलपर्स कुछ बहुत कम स्तर कोड में 'आईएलओगर' मुखौटा का संदर्भ दे रहे हैं। यह मुझे एक बुरा महसूस करता है। – Gusdor

+1

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

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