2009-06-30 40 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。