2012-07-13 21 views
6

मेरे पास AdoNetAppender का उपयोग कर डेटाबेस लॉगिंग है। मैं क्या करना चाहता हूं प्रत्येक लॉग स्टेटमेंट पर उपयोगकर्ता पहचान लॉग करें। हालांकि, मैं दो कारणों से मानक लॉग 4नेट% पहचान पैरामीटर का उपयोग नहीं करना चाहता:कस्टम पैरामीटर के साथ log4net डेटाबेस लॉगिंग

  1. log4net चेतावनी देता है कि इसकी संदर्भ धीमी है क्योंकि इसे संदर्भ पहचान को देखना है।
  2. कुछ सेवा घटकों में मानक पहचान एक सेवा खाता है लेकिन हमने पहले से ही एक चर में उपयोगकर्ता पहचान पर कब्जा कर लिया है और मैं इसका उपयोग करना चाहता हूं।

मैं कोड जहां कुछ लोगों को log4net.ThreadContext का उपयोग अतिरिक्त गुण जोड़ने के लिए देखा है, लेकिन मैं समझता हूँ कि इस सूत्र इंटरलिविंग की वजह से 'असुरक्षित' है (और यह भी एक प्रदर्शन नाली है)।

मेरे दृष्टिकोण AdoNetAppenderParameter वर्ग इस प्रकार का विस्तार करने में किया गया है:

public class UserAdoNetAppenderParameter : AdoNetAppenderParameter 
{ 

    public UserAdoNetAppenderParameter() 
    { 
     DbType = DbType.String; 
     PatternLayout layout = new PatternLayout(); 
     Layout2RawLayoutAdapter converter = new Layout2RawLayoutAdapter(layout); 
     Layout = converter; 
     ParameterName = "@username"; 
     Size = 255; 
    } 


    public override void Prepare(IDbCommand command) 
    {    
     command.Parameters.Add(this); 
    } 


    public override void FormatValue(IDbCommand command, LoggingEvent loggingEvent) 
    {    
     string[] data = loggingEvent.RenderedMessage.Split('~'); 
     string username = data[0]; 
     command.Parameters["@username"] = username; 
    } 

} 

और उसके बाद प्रोग्राम के रूप में इतनी तरह वर्तमान appender से जोड़ें:

ILog myLog = LogManager.GetLogger("ConnectionService"); 
IAppender[] appenders = myLog.Logger.Repository.GetAppenders(); 
AdoNetAppender appender = (AdoNetAppender)appenders[0];      

appender.AddParameter(new UserAdoNetAppenderParameter()); 

myLog.InfoFormat("{0}~{1}~{2}~{3}", userName, "ClassName", "Class Method", "Message"); 

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

मेरी समस्या यह है कि डेटाबेस में कोई लॉग स्टेटमेंट नहीं लिखा गया है। विचित्र रूप से, जब डीबगिंग करते हैं, तो FormatValue() विधि में एक ब्रेकपॉइंट केवल तब होता है जब मैं सेवा को रोकता हूं।

मैंने इससे संबंधित सामानों के भार से गुजर लिया है लेकिन अभी तक कोई जवाब नहीं मिला है। क्या कोई ऐसा करने में कामयाब रहा है, या मैं गलत निशान पर हूं। पीएस मैंने AdoNetAppender को विस्तारित करने का भी प्रयास किया है लेकिन यह आपको पैरामीटर मान सेट करने के लिए उपयोग नहीं करता है।

उत्तर

4

कुछ प्रयोगों के बाद, मुझे अंत में यह काम करने के लिए मिला। यह सुनिश्चित करना कि लॉग 4नेट के आंतरिक लॉगिंग ने त्रुटियों की पहचान करने और log4net स्रोत कोड डाउनलोड करने और AdoNetAppender पैरामीटर श्रेणी की समीक्षा करने में मदद की है, यह दिखाता है कि FormatValue() विधि का उपयोग कैसे किया जाना चाहिए।

public class UserAdoNetAppenderParameter : AdoNetAppenderParameter 
{   

    public override void FormatValue(IDbCommand command, LoggingEvent loggingEvent) 
    {    
     string[] data = loggingEvent.RenderedMessage.Split('~'); 
     string username = string.Empty; 
     if (data != null && data.Length >= 1) 
      username = data[0]; 

     // Lookup the parameter 
     IDbDataParameter param = (IDbDataParameter)command.Parameters[ParameterName]; 

     // Format the value 
     object formattedValue = username; 

     // If the value is null then convert to a DBNull 
     if (formattedValue == null) 
     { 
      formattedValue = DBNull.Value; 
     } 

     param.Value = formattedValue; 
    } 

} 

और यह उपयोग करने के लिए, मैं इस तरह log4net कॉन्फ़िग फ़ाइल में जोड़ें::

<parameter type="MyAssembly.Logging.UserAdoNetAppenderParameter, MyAssembly"> 
<parameterName value="@username" /> 
<dbType value="String" /> 
<size value="255" /> 
<layout type="log4net.Layout.PatternLayout" value="%message" /> 
</parameter> 

और प्रथा के अनुसार, मेरी लॉग बयान की तरह कुछ हो जाएगा तो, यहाँ संशोधन कस्टम appender पैरामीटर है इस:

if (log.IsDebugEnabled) 
    log.DebugFormat("{0}~{1}~{2}", username, someOtherParameter, message); 

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

2

हां, थ्रेड चपलता का मतलब है कि आपको सही डेटा वापस नहीं मिल सकता है। Log4net के लिए, आप इसे अपने HttpContext's Items collection में चिपकाना चाहेंगे।

समस्या यह है कि आपको डेटाबेस में उन मानों को लिखने का समय होने पर इसे वापस करने के लिए कुछ काम करना होगा क्योंकि इसने हमेशा मेरे लिए कंटेंट काम करने के लिए Marek's Adaptive Property Provider class का उपयोग किया है।

log4net.ThreadContext.Properties["UserName"] = AdaptivePropertyProvider.Create("UserName", Thread.CurrentPrincipal.Identity.Name); 

अनुकूली संपत्ति जब log4net यह अनुरोध करता है मान प्राप्त करने के लिए उपयुक्त जगह पता चल जाएगा: यह रूप में तुम सब करने की है निम्नलिखित है इसका इस्तेमाल करने की ही आसान है।

वैकल्पिक विकल्प

आप log4net के साथ फंस रहे हैं, NLog क्योंकि वे मूल रूप से ASP.NET अनुप्रयोगों का समर्थन ASP.NET वेबसाइटों रास्ता अधिक सरल के लिए प्रवेश करता है। उपयोग और यहां तक ​​कि कॉन्फ़िगरेशन log4net के लगभग समान है!

+1

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

5

मैं भी संरचित डेटा लॉग इन करने की जरूरत है और इस तरह प्रवेश इंटरफ़ेस का उपयोग करना पसंद:

log.Debug(new { 
    SomeProperty: "some value", 
    OtherProperty: 123 
}) 

तो मैं भी काम करने के लिए कस्टम AdoNetAppenderParameter वर्ग ने लिखा है:

public class CustomAdoNetAppenderParameter : AdoNetAppenderParameter 
{ 
    public override void FormatValue(IDbCommand command, LoggingEvent loggingEvent) 
    { 
     // Try to get property value 
     object propertyValue = null; 
     var propertyName = ParameterName.Replace("@", ""); 

     var messageObject = loggingEvent.MessageObject; 
     if (messageObject != null) 
     { 
      var property = messageObject.GetType().GetProperty(propertyName); 
      if (property != null) 
      { 
       propertyValue = property.GetValue(messageObject, null); 
      } 
     } 

     // Insert property value (or db null) into parameter 
     var dataParameter = (IDbDataParameter)command.Parameters[ParameterName]; 
     dataParameter.Value = propertyValue ?? DBNull.Value; 
    } 
} 

अब log4net विन्यास कर सकते हैं दिए गए ऑब्जेक्ट की किसी भी प्रॉपर्टी को लॉग इन करने के लिए इस्तेमाल किया जाए:

<?xml version="1.0" encoding="utf-8"?> 
<log4net> 
    <appender name="MyAdoNetAppender" type="log4net.Appender.AdoNetAppender"> 
     <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> 
     <connectionString value="... your connection string ..." /> 
     <commandText value="INSERT INTO mylog ([level],[someProperty]) VALUES (@log_level,@SomeProperty)" /> 

     <parameter> 
      <parameterName value="@log_level" /> 
      <dbType value="String" /> 
      <size value="50" /> 
      <layout type="log4net.Layout.PatternLayout"> 
       <conversionPattern value="%level" /> 
      </layout> 
     </parameter> 

     <parameter type="yourNamespace.CustomAdoNetAppenderParameter, yourAssemblyName"> 
      <parameterName value="@SomeProperty" /> 
      <dbType value="String" /> 
      <size value="255" /> 
     </parameter> 
    </appender> 

    <root> 
     <level value="DEBUG" /> 
     <appender-ref ref="MyAdoNetAppender" /> 
    </root> 
</log4net> 
संबंधित मुद्दे