log4net过滤器-如何编写AND过滤器以忽略日志消息

14

我在编写log4net的AND条件过滤器时遇到了困难。如果是nLog,我可以这样编写:

<logger name="*" minlevel="Info" xsi:type="NLogLoggerRule" writeTo="FooLogger" >
  <filters>
    <when condition="equals('${event-context:item=UserID}', 'TESTUSER') 
                 and equals('${event-context:item=URL}','/foo/foobar.aspx')" 
          action="Ignore" />
  </filters>
</logger>

我不确定如何在log4net中编写相同的过滤器。到目前为止,我已成功地编写了单个条件:

<appender>
   ....
   <filter type="log4net.Filter.PropertyFilter">
      <key value="URL" />
      <stringToMatch value="/foo/foobar.aspx" />
      <acceptOnMatch value="false" />
   </filter>
</appender>

如何使用log4net过滤器编写AND条件?请帮忙。

2个回答

26

支持AND条件的自定义过滤器。该类公开了Filter属性,因此可以在此处使用现有的log4net过滤器,并且如果需要,还可以具有嵌套的AND条件。

public class AndFilter : FilterSkeleton
{
    private bool acceptOnMatch;
    private readonly IList<IFilter> filters = new List<IFilter>();

    public override FilterDecision Decide(LoggingEvent loggingEvent)
    {
        if (loggingEvent == null)
            throw new ArgumentNullException("loggingEvent");

        foreach(IFilter filter in filters)
        {
            if (filter.Decide(loggingEvent) != FilterDecision.Accept)
                return FilterDecision.Neutral; // one of the filter has failed
        }

        // All conditions are true
        if(acceptOnMatch)
            return FilterDecision.Accept;
        else
            return FilterDecision.Deny;
    }

    public IFilter Filter 
    { 
        set { filters.Add(value); }
    }

    public bool AcceptOnMatch
    {
        get { return acceptOnMatch;}
        set { acceptOnMatch = value;}
    }
}

配置:

<filter type="Namespace.AndFilter, Assembly">
  <filter type="log4net.Filter.PropertyFilter">
    <key value="URL" />
    <stringToMatch value="/foo/foobar.aspx" />
  </filter>
  <filter type="log4net.Filter.PropertyFilter">
    <key value="UserID" />
    <stringToMatch value="TESTUSER" />
  </filter>
  <acceptOnMatch value="false" />
</filter>

1
是的,我也想到了复合过滤器(就像你的AddFilter一样),但是没有想到如何通过配置添加内部过滤器。这真是个很酷的技巧 :) 公共IFilter过滤器{设置{filters.Add(value); }} - Sergey Berezovskiy
2
谢谢,帮了大忙。可惜这不是标准的log4net功能。 - Johnny_D
我将“命名空间”更改为放置AndFilter代码的命名空间,但在log4net调试跟踪中出现了错误:“System.IO.FileNotFoundException:无法加载文件或程序集'Assembly'或其某个依赖项” - 我应该将“Assembly”更改为什么?如果我的项目名称是MSC并且它创建了一个MSC.dll,那么它会是“MSC”(但这没有起作用)。 - Matt Kemp
即使现在,这仍然是一段非常有用的代码。 - John Go-Soco

8

您可以为您的业务需求创建自定义过滤器:

public class UserRequestFilter : FilterSkeleton
{
    public override FilterDecision Decide(LoggingEvent loggingEvent)
    {
        if (loggingEvent == null)
            throw new ArgumentNullException("loggingEvent");

        string userId = (string)loggingEvent.Properties["UserId"];
        string url = (string)loggingEvent.Properties["Url"];

        if (String.IsNullOrEmpty(UserId) || String.IsNullOrEmpty(Url))
            return FilterDecision.Neutral;

        if (UserId.Equals(userId) && Url.Equals(url, StringComparison.CurrentCultureIgnoreCase))
            return AcceptOnMatch ? FilterDecision.Accept : FilterDecision.Deny;

        return FilterDecision.Neutral;
    }

    public bool AcceptOnMatch { get; set; }
    public string UserId { get; set; }
    public string Url { get; set; }
}

配置将如下所示:

<filter type="Namespace.UserRequestFilter, Assembly">
  <userId value="TESTUSER"/>
  <url value="/foo/foobar.aspx"/>
  <acceptOnMatch value="true"/>
</filter>

你也可以创建复合过滤器,但我没有找到在配置中使用它的方法。看起来它只能以编程方式附加(这是无用的^_^):

IAppenderAttachable logger = (IAppenderAttachable)_log.Logger;
AppenderSkeleton appender = (AppenderSkeleton)logger.GetAppender("appenderName");
CompoundFilter compoundFilter = new CompoundFilter();
compoundFilter.AddFilter(new PropertyFilter() { Key = "UserId", StringToMatch = "TEST" });
compoundFilter.AddFilter(new PropertyFilter() { Key = "Url", StringToMatch = @"/foo/foobar.aspx" });
appender.AddFilter(compoundFilter);
logger.AddAppender(appender);

[更新]

这里有一个技巧,你可以创建一个过滤器,它将检查所有下游的过滤器链:

public class DenyAllSubsequentFilter : FilterSkeleton
{
    public override FilterDecision Decide(LoggingEvent loggingEvent)
    {
        IFilter nextFilter = Next;
        if (nextFilter == null)
            return FilterDecision.Accept;

        while (nextFilter != null)
        {
            if (nextFilter.Decide(loggingEvent) != FilterDecision.Deny)
                return FilterDecision.Accept;

            nextFilter = nextFilter.Next;
        }

        return FilterDecision.Deny;
    }
}

使用方法:

<filter type="Namespace.DenyAllSubsequentFilter, Assembly"/>
<filter type="log4net.Filter.PropertyFilter">
  <key value="UserId" />
  <stringToMatch value="TEST" />
  <acceptOnMatch value="false" />
</filter>
<filter type="log4net.Filter.PropertyFilter">
  <key value="Url" />
  <stringToMatch value="/foo/foobar.aspx" />
  <acceptOnMatch value="false" />
</filter>

如果所有后续过滤器都拒绝记录消息,则此过滤器将拒绝记录消息。


谢谢@lazyberezovsky!实际上,我正在寻找支持AND条件的内置过滤器。但是,在意识到log4net不支持之后,我编写了一个自定义的AndFilter,它对我们有用。我将分享代码以造福他人: - Narayan Akhade

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接