Dựa trên nhu cầu chi tiết của OP được giải thích trong các nhận xét , một giải pháp thích hợp hơn tồn tại. OP nói rằng anh ấy muốn thêm dữ liệu tùy chỉnh vào nhật ký của nó với log4net, dữ liệu liên quan đến các yêu cầu.
Thay vì gói mỗi cuộc gọi log4net thành một lệnh gọi nhật ký tập trung tùy chỉnh xử lý việc truy xuất dữ liệu liên quan đến yêu cầu (trên mỗi cuộc gọi nhật ký), log4net có từ điển ngữ cảnh để thiết lập dữ liệu bổ sung tùy chỉnh để ghi nhật ký. Việc sử dụng các phân số đó cho phép định vị dữ liệu nhật ký yêu cầu của bạn cho yêu cầu hiện tại tại sự kiện BeginRequest, sau đó loại bỏ nó trong sự kiện EndRequest. Bất kỳ đăng nhập nào ở giữa sẽ được hưởng lợi từ những dữ liệu tùy chỉnh đó.
Và những thứ không xảy ra trong ngữ cảnh yêu cầu sẽ không cố gắng ghi dữ liệu liên quan đến yêu cầu, loại bỏ nhu cầu kiểm tra tính khả dụng của yêu cầu. Giải pháp này phù hợp với nguyên tắc mà Arman McHitaryan đã đề xuất trong câu trả lời của mình .
Để giải pháp này hoạt động, bạn cũng sẽ cần một số cấu hình bổ sung trên các trình phụ log4net để chúng ghi dữ liệu tùy chỉnh của bạn.
Giải pháp này có thể dễ dàng thực hiện như một mô-đun nâng cao nhật ký tùy chỉnh. Đây là mã mẫu cho nó:
using System;
using System.Web;
using log4net;
using log4net.Core;
namespace YourNameSpace
{
public class LogHttpModule : IHttpModule
{
public void Dispose()
{
// nothing to free
}
private const string _ipKey = "IP";
private const string _urlKey = "URL";
private const string _refererKey = "Referer";
private const string _userAgentKey = "UserAgent";
private const string _userNameKey = "userName";
public void Init(HttpApplication context)
{
context.BeginRequest += WebAppli_BeginRequest;
context.PostAuthenticateRequest += WebAppli_PostAuthenticateRequest;
// All custom properties must be initialized, otherwise log4net will not get
// them from HttpContext.
InitValueProviders(_ipKey, _urlKey, _refererKey, _userAgentKey,
_userNameKey);
}
private void InitValueProviders(params string[] valueKeys)
{
if (valueKeys == null)
return;
foreach(var key in valueKeys)
{
GlobalContext.Properties[key] = new HttpContextValueProvider(key);
}
}
private void WebAppli_BeginRequest(object sender, EventArgs e)
{
var currContext = HttpContext.Current;
currContext.Items[_ipKey] = currContext.Request.UserHostAddress;
currContext.Items[_urlKey] = currContext.Request.Url.AbsoluteUri;
currContext.Items[_refererKey] = currContext.Request.UrlReferrer != null ?
currContext.Request.UrlReferrer.AbsoluteUri : null;
currContext.Items[_userAgentKey] = currContext.Request.UserAgent;
}
private void WebAppli_PostAuthenticateRequest(object sender, EventArgs e)
{
var currContext = HttpContext.Current;
// log4net doc states that %identity is "extremely slow":
// http://logging.apache.org/log4net/release/sdk/log4net.Layout.PatternLayout.html
// So here is some custom retrieval logic for it, so bad, especialy since I
// tend to think this is a missed copy/paste in that documentation.
// Indeed, we can find by inspection in default properties fetch by log4net a
// log4net:Identity property with the data, but it looks undocumented...
currContext.Items[_userNameKey] = currContext.User.Identity.Name;
}
}
// General idea coming from
// http://piers7.blogspot.fr/2005/12/log4net-context-problems-with-aspnet.html
// We can not use log4net ThreadContext or LogicalThreadContext with asp.net, since
// asp.net may switch thread while serving a request, and reset the call context
// in the process.
public class HttpContextValueProvider : IFixingRequired
{
private string _contextKey;
public HttpContextValueProvider(string contextKey)
{
_contextKey = contextKey;
}
public override string ToString()
{
var currContext = HttpContext.Current;
if (currContext == null)
return null;
var value = currContext.Items[_contextKey];
if (value == null)
return null;
return value.ToString();
}
object IFixingRequired.GetFixedObject()
{
return ToString();
}
}
}
Thêm nó vào trang web của bạn, mẫu conf IIS 7+:
<system.webServer>
<!-- other stuff removed ... -->
<modules>
<!-- other stuff removed ... -->
<add name="LogEnhancer" type="YourNameSpace.LogHttpModule, YourAssemblyName" preCondition="managedHandler" />
<!-- other stuff removed ... -->
</modules>
<!-- other stuff removed ... -->
</system.webServer>
Và thiết lập trình phụ để ghi các thuộc tính bổ sung đó, cấu hình mẫu:
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<!-- other stuff removed ... -->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message - %property%newline%exception" />
</layout>
</appender>
<appender name="SqlAppender" type="log4net.Appender.AdoNetAppender">
<!-- other stuff removed ... -->
<commandText value="INSERT INTO YourLogTable ([Date],[Thread],[Level],[Logger],[UserName],[Message],[Exception],[Ip],[Url],[Referer],[UserAgent]) VALUES (@log_date, @thread, @log_level, @logger, @userName, @message, @exception, @Ip, @Url, @Referer, @UserAgent)" />
<!-- other parameters removed ... -->
<parameter>
<parameterName value="@userName" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{userName}" />
</layout>
</parameter>
<parameter>
<parameterName value="@Ip"/>
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{Ip}" />
</layout>
</parameter>
<parameter>
<parameterName value="@Url"/>
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{Url}" />
</layout>
</parameter>
<parameter>
<parameterName value="@Referer"/>
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{Referer}" />
</layout>
</parameter>
<parameter>
<parameterName value="@UserAgent"/>
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{UserAgent}" />
</layout>
</parameter>
</appender>
<!-- other stuff removed ... -->
</log4net>