2009-06-30 17 views
5

मैं लॉग 4नेट कॉन्फ़िगरेशन पर काम कर रहा हूं जो सभी अनचाहे अपवादों को लॉग करेगा। प्रत्येक लॉग एंट्री में जोड़े जाने के लिए मुझे उपयोगकर्ता के आधार पर कुछ गुणों की आवश्यकता है। मैंने इसे अपने application_Error ईवेंट में निम्न तरीके से सफलतापूर्वक सेट अप किया है। यहां मेरा पूरा global.asaxLog4Net, ThreadContext, और Global.asax

Imports log4net 
Imports log4net.Config 

    Public Class Global_asax 
     Inherits System.Web.HttpApplication 

     'Define a static logger variable 
     Private Shared log As ILog = LogManager.GetLogger(GetType(Global_asax)) 

     Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs) 
      ' Fires when the application is started 
      ConfigureLogging() 
     End Sub 

     Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs) 
      ' Code that runs when an unhandled error occurs 
      Dim ex As Exception = Server.GetLastError() 
      ThreadContext.Properties("user") = User.Identity.Name 
      ThreadContext.Properties("appbrowser") = String.Concat(Request.Browser.Browser, " ", Request.Browser.Version) 
      If TypeOf ex Is HttpUnhandledException AndAlso ex.InnerException IsNot Nothing Then 
       ex = ex.InnerException 
      End If 
      log.Error(ex) 
      ThreadContext.Properties.Clear() 
     End Sub 

     Private Sub ConfigureLogging() 
      Dim logFile As String = Server.MapPath("~/Log4Net.config") 
      log4net.Config.XmlConfigurator.ConfigureAndWatch(New System.IO.FileInfo(logFile)) 
      log4net.GlobalContext.Properties("appname") = System.Reflection.Assembly.GetExecutingAssembly.GetName.Name 
     End Sub 
    End Class 

ऐसा लगता है कि यह ठीक काम कर रहा है। हालांकि, मेरे पास कुछ प्रश्न हैं जो मैं जवाब देने में असमर्थ हूं।

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

धन्यवाद

उत्तर

11

यह सुरक्षित नहीं है ThreadContext ऐसे ही में अनुरोध-विशिष्ट मान लोड करने के लिए। कारण यह है कि एएसपी.NET ने सेवा अनुरोधों के लिए धागे साझा किए। यह वास्तव में, वास्तव में यह अक्सर करता है।

आप इसके बजाय LogicalThreadContext का उपयोग कर सकते हैं, हालांकि यह केवल कॉल कॉन्टेक्स्ट में मानों को संग्रहीत करता है, जिसका उपयोग रिमोटिंग के लिए किया जाता है।

AFAIK कोई HttpContext विशिष्ट संदर्भ भंडारण नहीं है, तो आप अपने थ्रेड संदर्भ के रूप में "मूल्य प्रदाता" उदाहरण असाइन कर सकते हैं, और रनटाइम पर यह मूल्य प्राप्त करने के लिए इस कक्षा पर .toString() को कॉल करेगा।

public class HttpContextUserProvider 
{ 
    public override string ToString() 
    { 
     return HttpContext.Current.User.Identity.Name; 
    } 
} 

यह आदर्श से कम है, लेकिन यह काम करता है।

+1

अगर आप एचटीपीकॉन्टेक्स्ट के बाद समानांतर कोडिंग का उपयोग करते हैं तो सावधान रहें। अगर वे लॉग में जोड़ते हैं तो किसी भी कार्यकर्ता धागे को वर्तमान में कॉपी करने की आवश्यकता हो सकती है। –

+0

global.asax.cs में आप कॉल को HttpContextUserProvider पर डाल देंगे? – Rory

+0

एएसपी.Net में एक संदर्भ विशिष्ट भंडारण है। यहां देखें: http://msdn.microsoft.com/en-us/library/system.web.httpcontext.items.aspx – MatteoSp

5

बेन का उत्तर सही है।

हालांकि, कुछ अन्य उपयोगकर्ताओं की तरह, मैं अभी भी आगे बढ़ने के तरीके पर थोड़ा सा खो गया था। यह log4net Context problems with ASP.Net thread agility पोस्ट और विशेष रूप से यह Marek Stój's Blog - log4net Contextual Properties and ASP.NET कुछ उत्कृष्ट कोड उदाहरणों के साथ समस्या के लिए कुछ और संदर्भ देता है।

मैं अत्यधिक मरेक स्टोज के कार्यान्वयन की अनुशंसा करता हूं, हालांकि ThreadContext.Properties["UserName"] को मेरे मामले में ThreadContext.Properties["User"] के साथ प्रतिस्थापित करने की आवश्यकता है।

मैंने अपने लॉगर क्लास में एक BeginRequest विधि जो मैं एप्लिकेशन_AuthenticateRequest से कॉल करता हूं जो सभी प्रासंगिक log4net गुणों को लोड करता है।

protected void Application_AuthenticateRequest(object sender, EventArgs e) 
{ 
    Logger.BeginRequest(Request); 
} 

और विधि कोड:

public static void BeginRequest(System.Web.HttpRequest request) 
{ 
    if (request == null) return; 

    ThreadContext.Properties["ip_address"] = AdaptivePropertyProvider.Create("ip_address", IPNetworking.GetMachineNameAndIP4Address()); 
    ThreadContext.Properties["rawUrl"] = AdaptivePropertyProvider.Create("rawUrl", request.RawUrl); 

    if (request.Browser != null && request.Browser.Capabilities != null) 
     ThreadContext.Properties["browser"] = AdaptivePropertyProvider.Create("browser", request.Browser.Capabilities[""].ToString()); 

    if (request.IsAuthenticated && HttpContext.Current.User != null) 
     ThreadContext.Properties["User"] = AdaptivePropertyProvider.Create("user", HttpContext.Current.User.Identity.Name); 
} 

मैंने पाया मैं बजाय विधि के भीतर HttpContext.Current.Request का उपयोग करने का अनुरोध वस्तु में पारित करने के लिए किया था। अन्यथा मैं उपयोगकर्ता और प्रमाणीकरण जानकारी खो देंगे। ध्यान दें कि IPNetworking कक्षा मेरा है इसलिए आपको क्लाइंट आईपी प्राप्त करने की अपनी विधि प्रदान करने की आवश्यकता होगी। AdaptivePropertyProvider कक्षा सीधे मरेक स्टोज से है।

+1

यह अनुकूली प्रॉपर्टी ऑब्जेक्ट को 'TheadContext' गुण संग्रह में असाइन करता है, लेकिन प्रारंभिक समस्या नहीं थी जिसे हम उस संग्रह पर सही ढंग से बने रहने के लिए भरोसा नहीं कर सके? मुझे लगता है कि अनुकूली संपत्ति हैंडलर को वैश्विक संदर्भ में एक संपत्ति के रूप में असाइन किया जाना चाहिए ... – starwed

+0

मुझे यकीन नहीं है कि वैश्विक वस्तु किस प्रकार लागू होगी, हम लॉग इन करने का प्रयास कर रहे हैं, इस मामले में, एक दिया गया वेब सत्र, तो मूल्य व्यक्तिगत धागे द्वारा संदर्भित किया जाएगा, सही? – Shane