我目前将所有log4net事件都写到数据库中,并且看起来工作正常。要捕获已登录的用户帐户,请使用以下代码:
HttpContext context = HttpContext.Current; if (context != null && context.User != null && context.User.Identity.IsAuthenticated) { MDC.Set("user", HttpContext.Current.User.Identity.Name); }
该代码看起来还可以,除了没有与用户上下文关联的事件(即,我们公共网页上的用户)。在这种情况下,log4net捕获似乎有时会写入最后登录的用户帐户(错误),有时会写入null(良好)。任何人都可以在所有情况下可靠地使用此功能吗?我相信我看到一条注释,即不再推荐使用MDC功能,但是找不到任何推荐的替代产品。
注意:我为MDC设置了帐户名感到很奇怪,但是如果没有用户处于活动状态,则永远不会清除它。那可能是问题的一部分。但是,我没有找到任何可以清除用户名的MDC代码提取。
如果HttpContext中可用的信息足够,也就是说,如果您发布的示例代码为您提供了正确的答案(MDC问题除外),而您只是不写:
经常,那么您可以通过为log4net编写自己的自定义PatternLayoutConverter来将用户名“自动”添加到日志中。它们非常易于编写,您可以像内置的日志记录一样在log4net日志记录配置中对其进行配置。
有关如何编写自定义PatternLayoutConverter的一个示例,请参见此问题:
自定义log4net属性PatternLayoutConverter(带有索引)
使用该链接上的示例,您可能可以执行以下操作:
namespace Log4NetTest { class HttpContextUserPatternConverter : PatternLayoutConverter { protected override void Convert(System.IO.TextWriter writer, LoggingEvent loggingEvent) { string name = ""; HttpContext context = HttpContext.Current; if (context != null && context.User != null && context.User.Identity.IsAuthenticated) { name = context.User.Identity.Name; } writer.Write(name); } } }
您可以在log4net中对此进行配置,如下所示:
//Log HttpContext.Current.User.Identity.Name <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="%d [%t] %-5p [User = %HTTPUser] %m%n"/> <converter> <name value="HTTPUser" /> <type value="Log4NetTest.HttpContextUserPatternConverter" /> </converter> </layout>
此外,您可以构建其他使用Option参数的模式转换器(请参阅上面的链接中的示例),以从HttpContext.Current.Items或HttpContext.Current.Session集合中提取特定项。
就像是:
namespace Log4NetTest { class HttpContextSessionPatternConverter : PatternLayoutConverter { protected override void Convert(System.IO.TextWriter writer, LoggingEvent loggingEvent) { //Use the value in Option as a key into HttpContext.Current.Session string setting = ""; HttpContext context = HttpContext.Current; if (context != null) { object sessionItem; sessionItem = context.Session[Option]; if (sessionItem != null) { setting = sessionItem.ToString(); } writer.Write(setting); } } } } namespace Log4NetTest { class HttpContextItemPatternConverter : PatternLayoutConverter { protected override void Convert(System.IO.TextWriter writer, LoggingEvent loggingEvent) { //Use the value in Option as a key into HttpContext.Current.Session string setting = ""; HttpContext context = HttpContext.Current; if (context != null) { object item; item = context.Items[Option]; if (item != null) { setting = item.ToString(); } writer.Write(setting); } } } }
您可能还会发现以下链接有用:
http://piers7.blogspot.com/2005/12/log4net-context-problems-with- aspnet.html
在这里,博客作者提出了一种与我提出的方法不同的解决方案,用于从HttpContext记录值。阅读博客文章,查看他对问题的描述以及解决方案。为了总结解决方案,他将一个对象存储在GlobalDiagnosticContext(MDC的更现代名称)中。当log4net记录对象的值时,它使用ToString()。他的对象的实现从HttpContext检索一个值:
因此,您可以执行以下操作:
public class HttpContextUserNameProvider { public override string ToString() { HttpContext context = HttpContext.Current; if (context != null && context.User != null && context.User.Identity.IsAuthenticated) { return context.Identity.Name; } return ""; } }
您可以在程序的早期将这个对象的实例放在GlobalDiagnosticContext(MDC)中,由于它正在访问HttpContext.Current,因此它将始终返回正确的值。
MDC.Set("user", new HttpContextUserNameProvider());
这似乎比我建议的要容易得多!
为了完整起见,如果有人想知道如何在NLog中执行相同的操作,则NLog似乎可以通过其“ aspnet-*” LayoutRenderers提供大多数/所有HttpContext信息:
https://github.com/nlog/nlog/wiki/Layout- Renderers