0

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

  • Side thought: One possible workaround would be to put each Form in its own apartement-thread, and distinguish the log events via thread-name. But then I'd need to synchronize/"thread-safify" all inter-form-events, right? This might be a maintenance PITA... has someone a better idea? – Dr. Tim dos Santos Aug 31 '15 at 06:47

1 Answers1

0

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);
            }
        }    
    }
}
stuartd
  • 70,509
  • 14
  • 132
  • 163
  • thx, yes, this solves the direct problem, but I also have cases where a GUI event in one form is handled (indirectly) in several of those forms (e.g., in the event origin form and one other form). In such a case, I still cannot see what happens in what form. Is there a possibility to distinguish in those more complex cases? – Dr. Tim dos Santos Aug 25 '15 at 05:07
  • @Dr.TimdosSantos in that case, you would probably use the [ThreadContext class's Stacks property](https://logging.apache.org/log4net/release/sdk/log4net.ThreadContext.html) – stuartd Aug 25 '15 at 10:02
  • could you please elaborate how to leverage the ThreadContext.Stacks prop to do this, without having to put a `using (ThreadContext.Stacks["Foo"].Push("Blah")) {...}` call in each and every UI event handler? – Dr. Tim dos Santos Aug 31 '15 at 04:54
  • @Dr.TimdosSantos edited answer to show multiple values on the stack - which you have to clear after use. – stuartd Sep 02 '15 at 09:51
  • Thanks I'll look into that – Dr. Tim dos Santos Sep 03 '15 at 10:43