log4net filter - how to write AND filter to ignore log messages
Asked Answered
S

2

14

I am struggling to write an AND conditional filter in log4net. Had it been nLog, I could have written it this way:

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

I am not sure how to write the same filter in log4net. I have been so far successful, in writing a single condition:

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

How can I write AND conditions using log4net filters? Please help.

Scirrhus answered 22/12, 2011 at 12:45 Comment(0)
S
27

A custom filter supporting AND conditions. This class exposes Filter property so existing log4net filters can be used here and also one can have nested AND conditions if required.

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

Config:

<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>
Scirrhus answered 14/1, 2012 at 0:25 Comment(4)
Yeah, I also came up with compound filter (like as your AddFilter), but didn't figured how to add inner filters via config. That is really cool trick :) public IFilter Filter { set { filters.Add(value); } }Bopp
Thanks, helped. It's pity that this isn't a standard log4net feature.Chummy
I changed "Namespace" to the one where I put the AndFilter code and I got an error in the log4net debug trace "System.IO.FileNotFoundException: Could not load file or assembly 'Assembly' or one of its dependencies" - what should I change "Assembly" to? If the name of my project is MSC and it creates a MSC.dll would it be "MSC" (but this didn't work)Fidele
Still a very useful bit of code even now.Collected
B
9

You can create custom filter for your business needs:

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

Configuration will look like this:

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

Also you can create compound filter, but I didn't find way to use it in configuration. Looks like it could be attached only programmatically (which is useless ^_^):

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

[UPDATE]

Here is trick that you can use - create filter, which will check all filters down the filters chain:

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

Usage:

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

This filter will deny logging message if all subsequent filters will deny it.

Bopp answered 12/1, 2012 at 0:16 Comment(1)
Thanks @lazyberezovsky! Actually, I was looking for built-in filter which supports AND conditions. But, after realising that log4net doesn't support one, I wrote a custom AndFilter which worked for us. I will share code for benefit of others:Scirrhus

© 2022 - 2024 — McMap. All rights reserved.