ขึ้นอยู่กับความต้องการโดยละเอียดของ OP ที่อธิบายไว้ในความคิดเห็นมีวิธีแก้ปัญหาที่เหมาะสมกว่า OP ระบุว่าเขาต้องการเพิ่มข้อมูลที่กำหนดเองในบันทึกด้วย log4net ข้อมูลที่เกี่ยวข้องกับคำขอ
แทนที่จะรวมการเรียก log4net แต่ละครั้งไว้ในการเรียกบันทึกส่วนกลางที่กำหนดเองซึ่งจัดการการดึงข้อมูลที่เกี่ยวข้องกับคำขอ (ในการเรียกบันทึกแต่ละครั้ง) log4net มีพจนานุกรมบริบทสำหรับการตั้งค่าข้อมูลเพิ่มเติมที่กำหนดเองเพื่อบันทึก การใช้พจนานุกรมเหล่านั้นช่วยให้สามารถวางตำแหน่งข้อมูลบันทึกคำขอของคุณสำหรับคำขอปัจจุบันที่เหตุการณ์ BeginRequest จากนั้นจึงจะปิดที่เหตุการณ์ EndRequest การเข้าสู่ระบบใด ๆ ระหว่างจะได้รับประโยชน์จากข้อมูลที่กำหนดเองเหล่านั้น
และสิ่งที่ไม่เกิดขึ้นในบริบทคำขอจะไม่พยายามบันทึกข้อมูลที่เกี่ยวข้องกับคำขอทำให้ไม่จำเป็นต้องทดสอบความพร้อมของคำขอ วิธีนี้ตรงกับหลักการที่ Arman McHitaryan แนะนำในคำตอบของเขาคำตอบ
เพื่อให้โซลูชันนี้ใช้งานได้คุณจะต้องมีการกำหนดค่าเพิ่มเติมในส่วนผนวก log4net ของคุณเพื่อให้สามารถบันทึกข้อมูลที่คุณกำหนดเองได้
โซลูชันนี้สามารถนำไปใช้เป็นโมดูลการเพิ่มประสิทธิภาพการบันทึกแบบกำหนดเองได้อย่างง่ายดาย นี่คือโค้ดตัวอย่างสำหรับมัน:
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();
}
}
}
เพิ่มลงในไซต์ของคุณตัวอย่าง IIS 7+ conf:
<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>
และตั้งค่าตัวผนวกเพื่อบันทึกคุณสมบัติเพิ่มเติมเหล่านั้นตัวอย่าง config:
<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>