log4net: How to distinguish between different forms on the same UI thread?

224 Views Asked by At

is there a way (NDC, Properties, ...?) to have a name/id per form that is included in all log4net messages, so I can distinguish between the forms in all log messages?

I have many service methods etc. that are used in all my forms, and I'd like to see e.g. that a service was called as a result of user input in what form (think multiple nonmodal similar forms (same class), running in the same UI thread, containing a button, and in the button's Click-Event, a service method is called. Inside the service method, there are logging calls. In the log messages, I'd like to have a property containing the information of in exactly which form instance the button was clicked in).

I don't want to modify ALL logging calls. The examples in the web for log contexts / NDC all only talk about multiple clients / asp.net requests / etc., not multiple forms in 1 thread.

Thanks, Tim

1

There are 1 best solutions below

5
On BEST ANSWER

To do this, set the properties in the form's Activated event to what you want to log:

private void Form1_Activated(object sender, System.EventArgs e)
{
    // for example
    log4net.GlobalContext.Properties["Name"] = this.GetType().Name;
    log4net.GlobalContext.Properties["Id"] = this.Id;
}

The in your logging configuration, you can reference the properties in the PatternLayout for each appender:

<layout type="log4net.Layout.PatternLayout">
  <conversionPattern value="%property{Name} : %property{Id} : [%level]- %message%newline" />
</layout>

Edit: to preserve multiple values, use a stack, as in this unit test which outputs:

Now in TestClass1 Now in TestClass2

using log4net.Appender;
using log4net.Config;
using log4net.Core;
using log4net.Layout;
using NUnit.Framework;

namespace log4net.Tests
{
    [TestFixture] // A NUnit test
    public class log4net_Stacks
    {
        [SetUp]
        public void Setup()
        {
            ConsoleAppender ca = new ConsoleAppender
            {
                Layout = new PatternLayout("%property{demo}"),
                Threshold = Level.All
            };

            ca.ActivateOptions();
            BasicConfigurator.Configure(ca);
        }

        [Test]
        public void Stacks_Demo()
        {
            new TestClass1().Method1();
            LogManager.GetLogger("logger").Debug("");
            ThreadContext.Stacks["demo"].Clear();
        }

        private abstract class BaseTestClass
        {
            protected static void AddToStack(string message)
            {
                ThreadContext.Stacks["demo"].Push(message);
            }
        }

        private class TestClass1 : BaseTestClass
        {
            public void Method1()
            {
                AddToStack("Now in " + GetType().Name);
                var tc2 = new TestClass2();
                tc2.Method2();
            }
        }

        private class TestClass2 : BaseTestClass
        {
            public void Method2()
            {
                AddToStack("Now in " + GetType().Name);
            }
        }    
    }
}