views:

1049

answers:

2

I am working on a Log4Net configuration that will log all unhandled exceptions. I need certain properties, based on user, to be added to each log entry. I have set this up successfully in the following manner in my Application_Error event. Here is my complete 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

This appears to be working fine. However, I have some questions that I am unable to answer.

Is the way that I am adding the user specific properties, via the threadcontext, correct? Will this always log the correct information, even under load? When would you use threadlogicalcontext? Is there a better way to do this?

Thanks

A: 

Log4Net suggests your approach in their SDK reference http://logging.apache.org/log4net/release/sdk/log4net.ThreadContext.html

Jim
+3  A: 

It is not safe to load request-specific values into ThreadContext like that. The reason is that ASP.NET shared threads to service requests. It does this quite often, in fact.

You could instead use LogicalThreadContext, however that simply stores the values in Call Context, which is used for Remoting.

AFAIK there is no HttpContext specific context storage, so what you can do is instead assign a "value provider" instance as your thread context, and at runtime it will call .ToString() on this class to get the value.

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

It's less than ideal, but it works.

Ben Scheirman