使用 log4net 捕获用户名 [英] Capture username with log4net

查看:19
本文介绍了使用 log4net 捕获用户名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前将所有 log4net 事件写入数据库,它似乎工作得很好.为了捕获登录的用户帐户,我使用了这段代码:

I currently write all log4net events to a database, and it seems to work just fine. To capture the logged in user account I use this piece of code:

HttpContext context = HttpContext.Current;
if (context != null && context.User != null && context.User.Identity.IsAuthenticated)
{
    MDC.Set("user", HttpContext.Current.User.Identity.Name);
}

代码看起来没问题,除了没有关联用户上下文的事件(即我们公共网页上的用户).在这种情况下,log4net 捕获似乎有时会写入最后登录的用户帐户(坏),有时会写入空(好).任何人都可以使用此功能在所有情况下可靠地工作?我相信我看到一条说明 MDC 不再是推荐使用的功能,但我找不到任何推荐的替代品.

The code seems ok, except for events that have no user context associated with them (ie. a user on our public web page). In that case the log4net capture seems to sometime write the last logged in user account (bad) and sometime write a null (good). Anyone got this feature to work reliably in all cases? I believe I saw a note that MDC is no longer a recommended feature to use, but I wasn't able to find any alternatives that are recommended.

注意:我觉得奇怪的是 MDC 设置了一个帐户名,但如果没有用户处于活动状态,则永远不会清除.这可能是问题的一部分.但是,我没有找到任何也清除用户名的 MDC 代码提取.

Note: I find it odd that MDC is set with an account name, but never cleared if no user is active. That could be part of the problem. However, I didn't find any MDC code extracts that also clear the username.

推荐答案

如果 HttpContext 中可用的信息足够,也就是如果你贴的示例代码给了你正确的答案(MDC 问题除外)你宁愿不写:

If the information that is available in the HttpContext is sufficient, that is, if the sample code you posted gives you the right answer (except for the MDC issue) and you would just rather just not write:

HttpContext context = HttpContext.Current; 
if (context != null && context.User != null && context.User.Identity.IsAuthenticated)
{     
  MDC.Set("user", HttpContext.Current.User.Identity.Name); 
} 

通常情况下,您可以通过为 log4net 编写自己的自定义 PatternLayoutConverter 来自动"将用户名添加到您的日志中.它们非常容易编写,您可以在 log4net 日志记录配置中配置它们,就像内置的一样.

so often, then you might be able to add the username to your log "automatically" by writing your own custom PatternLayoutConverter for log4net. They are pretty easy to write and you can configure them in your log4net logging configuration just like the built in ones.

有关如何编写自定义 PatternLayoutConverter 的示例,请参阅此问题:

See this question for one example of how to write a custom PatternLayoutConverter:

自定义 log4net 属性 PatternLayoutConverter(带索引)

使用该链接中的示例,您可能可以执行以下操作:

Using the example at that link, you might be able to do something like this:

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 中进行如下配置:

You would configure this in log4net something like this:

  //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 集合中提取特定项目.

In addition, you could build other pattern converters that use the Option parameter (see the example at the link above) to pull a specific item from the HttpContext.Current.Items or HttpContext.Current.Session collections.

类似于:

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);
      }
    }
  }
}

您可能还会发现这些链接很有用:

You might also find these links useful:

http://piers7.blogspot.com/2005/12/log4net-context-problems-with-aspnet.html

在这里,博主提出了一种与我提出的不同的解决方案来记录来自 HttpContext 的值.阅读博客文章以查看他对问题的描述和他的解决方案.为了总结解决方案,他在 GlobalDiagnosticContext(MDC 的更现代名称)中存储了一个对象.当 log4net 记录对象的值时,它使用 ToString().他的对象的实现从 HttpContext 中检索一个值:

Here, the blogger proposes a different solution to logging values from HttpContext than what I proposed. Read the blog post to see his description of the problem and for his solution. To summarize the solution, he stores an object in the GlobalDiagnosticContext (the more modern name for MDC). When log4net logs the value of the object it uses ToString(). the Implementation of his object retrieves a value from the 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.

You can put an instance of this object in the GlobalDiagnosticContext (MDC) early in your program and it will always return the right value since it is accessing HttpContext.Current.

MDC.Set("user", new HttpContextUserNameProvider());

这似乎比我提出的要容易得多!

This seems a lot easier than what I proposed!

为了完整起见,如果有人想知道如何在 NLog 中做同样的事情,NLog 似乎通过其aspnet-*"LayoutRenderers 使大部分/所有 HttpContext 信息可用:

For completeness, if someone wants to know how to do the same thing in NLog, NLog appears to make most/all of the HttpContext information available through its "aspnet-*" LayoutRenderers:

https://github.com/nlog/nlog/wiki/Layout-Renderers

这篇关于使用 log4net 捕获用户名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆