Sim*_*com 19 c# asp.net logging log4net
我目前将所有log4net事件写入数据库,它似乎工作正常.要捕获登录的用户帐户,我使用以下代码:
HttpContext context = HttpContext.Current;
if (context != null && context.User != null && context.User.Identity.IsAuthenticated)
{
MDC.Set("user", HttpContext.Current.User.Identity.Name);
}
Run Code Online (Sandbox Code Playgroud)
代码似乎没问题,除了没有与之关联的用户上下文的事件(即我们公共网页上的用户).在这种情况下,log4net捕获似乎有时写入最后登录的用户帐户(坏),有时写入空(好).任何人都有这个功能在所有情况下都可靠地工作?我相信我看到一条说明MDC不再是推荐使用的功能,但我无法找到任何推荐的替代品.
注意:我发现MDC设置了帐户名称很奇怪,但如果没有用户处于活动状态,则永远不会清除.这可能是问题的一部分.但是,我没有找到任何也清除用户名的MDC代码提取.
wag*_*ghe 27
如果HttpContext中可用的信息足够,也就是说,如果您发布的示例代码为您提供了正确答案(MDC问题除外),您只是不想写:
HttpContext context = HttpContext.Current;
if (context != null && context.User != null && context.User.Identity.IsAuthenticated)
{
MDC.Set("user", HttpContext.Current.User.Identity.Name);
}
Run Code Online (Sandbox Code Playgroud)
通常,您可以通过为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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以在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>
Run Code Online (Sandbox Code Playgroud)
此外,您可以构建其他使用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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可能还会发现这些链接很有用:
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 "";
}
}
Run Code Online (Sandbox Code Playgroud)
您可以在程序的早期将此对象的实例放在GlobalDiagnosticContext(MDC)中,并且它将始终返回正确的值,因为它正在访问HttpContext.Current.
MDC.Set("user", new HttpContextUserNameProvider());
Run Code Online (Sandbox Code Playgroud)
这似乎比我提出的要容易得多!
为了完整性,如果有人想知道如何在NLog中做同样的事情,NLog似乎通过其"aspnet-*"LayoutRenderers使大部分/全部HttpContext信息可用:
https://github.com/nlog/nlog/wiki/Layout-Renderers
Gia*_*rdi 22
根据Log4Net 官方API文档,MDC已被弃用:
MDC已弃用,已被"属性"替换.当前的MDC实现转发到ThreadContext.Properties.
除此之外MDC.Set只接受字符串作为值,所以@wageoghe的最后一个解决方案无法工作(使用HttpContextUserNameProvider的解决方案)
我的解决方案是使用HttpContextUserNameProvider log4net.GlobalContext,也在官方API文档中建议:
在log4net初始化之后添加此immediatley(例如在Global.Application_Start中)
log4net.GlobalContext.Properties["user"] = new HttpContextUserNameProvider();
Run Code Online (Sandbox Code Playgroud)添加此课程
public class HttpContextUserNameProvider
{
public override string ToString()
{
HttpContext context = HttpContext.Current;
if (context != null && context.User != null && context.User.Identity.IsAuthenticated)
{
return context.User.Identity.Name;
}
return "";
}
}
Run Code Online (Sandbox Code Playgroud)通过添加"user"属性值来修改log4net配置,例如:
<layout type="log4net.Layout.PatternLayout" value="%property{user}"/>
Run Code Online (Sandbox Code Playgroud)Ben*_*ith 10
从Log4Net 1.2.11开始,您现在可以简单地使用appender模式通过ASP .NET请求获取授权用户,例如
%aspnet-request{AUTH_USER}
Run Code Online (Sandbox Code Playgroud)