【问题标题】:log4net filter - how to write AND filter to ignore log messageslog4net 过滤器 - 如何编写 AND 过滤器以忽略日志消息
【发布时间】:2011-12-22 12:45:53
【问题描述】:

我正在努力在 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 条件?请帮忙。

【问题讨论】:

    标签: log4net log4net-configuration log4net-filter


    【解决方案1】:

    支持 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>
    

    【讨论】:

    • 是的,我也想出了复合过滤器(就像你的 AddFilter 一样),但没有想出如何通过 config 添加内部过滤器。这真是很酷的把戏:) public IFilter Filter { set { filters.Add(value); } }
    • 谢谢,有帮助。可惜这不是标准的 log4net 功能。
    • 我将“命名空间”更改为放置 AndFilter 代码的位置,但在 log4net 调试跟踪中出现错误“System.IO.FileNotFoundException:无法加载文件或程序集‘Assembly’或一个它的依赖项”-我应该将“Assembly”更改为什么?如果我的项目名称是 MSC 并且它创建了一个 MSC.dll 会是“MSC”(但这不起作用)
    【解决方案2】:

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

    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 对我们有用。我将分享代码以造福他人:
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-11
    • 2012-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-07
    相关资源
    最近更新 更多