2009-06-30 71 views
5

我正在使用Log4Net配置來記錄所有未處理的異常。我需要將某些基於用戶的屬性添加到每個日誌條目中。我已經在我的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 

這似乎工作正常。但是,我有一些我無法回答的問題。

是我通過threadcontext添加用戶特定屬性的方式是否正確?即使在負載下,這是否會記錄正確的信息?你什麼時候會使用threadlogicalcontext?有一個更好的方法嗎?

感謝

回答

11

它是不安全的請求特定的值加載到ThreadContext這樣。原因是ASP.NET共享線程來處理請求。事實上,它經常這樣做。

但是,您可以改爲使用LogicalThreadContext,但只需將值存儲在用於遠程處理的呼叫上下文中。 AFAIK沒有HttpContext特定的上下文存儲,所以你可以做的是將一個「值提供者」實例指定爲你的線程上下文,在運行時它會調用這個類的.ToString()來獲取值。

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

它不是理想的,但它的工作原理。

+1

如果使用並行編碼,請小心謹慎,因爲如果將HttpContext.Current添加到日誌中,HttpContext.Current可能需要複製到任何工作線程。 – 2011-10-25 00:01:55

+0

在global.asax.cs中的哪個位置可以調用HttpContextUserProvider? – Rory 2012-08-19 17:31:56

5

本的答案是正確的。

但是,像其他一些用戶一樣,我仍然在如何繼續下去方面有點失落。這log4net Context problems with ASP.Net thread agility後,特別是這個Marek Stój's Blog - log4net Contextual Properties and ASP.NET一個給一些優秀的代碼示例問題的一些更多的上下文。

我強烈建議MarekStój的實施,儘管在我的情況下ThreadContext.Properties["UserName"]需要替換爲ThreadContext.Properties["User"]

我添加了一個BeginRequest方法到我的記錄器類,我從Application_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類是我自己的,因此您需要提供自己的獲取客戶端IP的方法。 AdaptivePropertyProvider課程直接來自MarekStój。