log4net - confgure to ignore messages from a specific thread

1.8k Views Asked by At

Is there a possibility to filter out log entries from a specific thread?

I use nunit for running tests (c#):

using System;
using NUnit.Core;
using log4net;

namespace Main
{
    public class Program
    {
        public static readonly ILogger log = LogManager.GetLogger(typeof(Program));

        static void Main(string[] args)
        {
            log.Info("start");

            TestPackage package = new TestPackage(@"C:\Test\Main.Tests.dll");
            RemoteTestRunner remoteTestRunner = new RemoteTestRunner();
            remoteTestRunner.Load(package);
            TestResult result = remoteTestRunner.Run(new NullListener(), TestFilter.Empty, true, LoggingThreshold.All);

            log.Info("end");
        }
    }
}

This is the logging I get:

INFO  17:57:24 [1] Main.Program - start
ERROR 17:57:25 [TestRunnerThread] Main.TestedClass - Exception! Relevant for production / okay in test
INFO  17:57:26 [1] Main.Program - end

log4net sends me a mail every time an ERROR is logged. If I run the test, I don't want to get those mails. nunit sets the thread-name to: "TestRunnerThread". How can I ignore this thread?

I've read this: How to log into separate files per thread with Log4Net? and tried this filter (and got no logs at all):

<filter type="log4net.Filter.PropertyFilter">
    <key value="threadId" />
    <stringToMatch value="TestRunnerThread" />
    <acceptOnMatch value="false" />
</filter>
2

There are 2 best solutions below

0
On

A few things:

  • As mentioned in the answer to the question you linked to, you must register a key-value-pair with ThreadContext in order for the filter key to work: ThreadContext.Properties["threadId"] = "1"
  • Filter order matters. From the docs:

    Filters form a chain that the event has to pass through. Any filter along the way can accept the event and stop processing, deny the event and stop processing, or allow the event on to the next filter. If the event gets to the end of the filter chain without being denied it is implicitly accepted and will be logged.

    Make sure the filter order is as follows:

    1. Filter for thread you don't want
      • If match, message is denied and not passed to next filter (due to <acceptOnMatch value="false" />
      • If not matched, message is passed on to next filter in chain
    2. Logger filter
      • If match, message is accepted and not passed to next filter
      • If not matched, message is passed on to next filter in chain
    3. Deny All
      • Message is denied

Full example:

<?xml version="1.0" encoding="utf-8"?>
<log4net>
    <appender type="log4net.Appender.ConsoleAppender" name="consoleApp">
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="%message%newline" />
        </layout>       
        <filter type="log4net.Filter.PropertyFilter">
            <key value="threadId" />
            <stringToMatch value="3" />
            <acceptOnMatch value="false" />
        </filter>
        <filter type="log4net.Filter.LoggerMatchFilter">
            <loggerToMatch value="sandbox" />
        </filter>
        <filter type="log4net.Filter.DenyAllFilter" />
    </appender>
    <root>
        <level value="ALL" />
        <appender-ref ref="consoleApp" />
    </root>
</log4net>
static void Main(string[] args)
{
    XmlConfigurator.Configure(new FileInfo("config.xml"));

    ILog log = LogManager.GetLogger("sandbox");

    ThreadPool.QueueUserWorkItem(a =>
    {
        ThreadContext.Properties["threadId"] = "1";
        log.Debug("one");
    });

    ThreadPool.QueueUserWorkItem(a =>
    {
        ThreadContext.Properties["threadId"] = "2";
        log.Debug("two");
    });

    ThreadPool.QueueUserWorkItem(a =>
    {
        ThreadContext.Properties["threadId"] = "3";
        log.Debug("three");
    });

    Console.Read();
}

Will log:

one
two

(possibly in a different order, depending on which thread completes first)

0
On

I haven't used log4net but a simple suggestion would be to change the id to something like [email protected] at the place where you specify the email id to receive logging emails...

Agreed there should be something to configure to not to send emails every time but this can be a workaround till you find a decent solution

While you are using logging, I would also suggest you to look at Microsoft Enterprise library logging application block. It is super easy to configure and use in your application.

Link http://msdn.microsoft.com/en-us/library/ff664569(v=pandp.50).aspx