2009-06-30 39 views
5

処理されていないすべての例外を記録するLog4Net構成で作業しています。私は、ユーザーに基づいて特定のプロパティを各ログエントリに追加する必要があります。これを私のApplication_Errorイベントで以下のようにして正常に設定しました。完全なglobal.asaxですLog4Net、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を使いますか?これを行うより良い方法はありますか?そのようなThreadContextに要求固有の値をロードすることは安全ではありません

おかげ

答えて

11

。その理由は、ASP.NETがサービス要求に対するスレッドを共有しているためです。これは実際にはこれをかなり頻繁に行います。

代わりにLogicalThreadContextを使用することもできますが、単にコールコンテキストに値を格納するだけで、これはRemotingに使用されます。

AFAIK HttpContext固有のコンテキスト記憶域がないので、代わりに "値プロバイダ"インスタンスをスレッドコンテキストとして割り当て、実行時にこのクラスの.ToString()を呼び出して値を取得します。

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

これは理想的ではありませんが、機能します。

+1

HttpContext.Currentがログに追加されたワーカースレッドにコピーする必要があるため、並列コードを使用する場合は注意が必要です。 –

+0

global.asax.csではHttpContextUserProviderを呼び出しますか? – Rory

+0

ASP.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"]に置き換える必要がありましたが、MarekStójの実装を強くお勧めします。

私は、関連するすべてのlog4netプロパティをロードするApplication_AuthenticateRequestから呼び出す私のLoggerクラスにBeginRequestメソッドを追加しました。

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を使用するRequestオブジェクトを渡す必要があったました。それ以外の場合は、ユーザーと認証情報が失われます。 IPNetworkingクラスは私自身のものなので、クライアントIPを取得する独自の方法を提供する必要があります。 AdaptivePropertyProviderクラスはMarekStójから直接です。

+1

これは、アダプティブプロパティオブジェクトを 'TheadContext'プロパティコレクションに割り当てますが、そのコレクションが正しく持続することを期待できなかった最初の問題ではありませんでしたか?私は適応プロパティハンドラがグローバルコンテキストのプロパティとして割り当てられる必要があると思います... – starwed

+0

私は、この場合、特定のWebセッションをログに記録しようとしている場合、どのような種類のグローバルオブジェクトが適用可能かはわかりませんが、値は個々のスレッドによって文脈化されるでしょうか? – Shane

関連する問題