log4net:如何区分同一UI线程上的不同形式?

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

有没有办法(NDC、Properties,...?)让每个表单包含在所有 log4net 消息中的 name/id,这样我就可以区分所有日志消息中的表单?

我有很多服务方法等用于我所有的表格,我想看看例如由于用户以何种形式输入而调用服务(想想多个非模态相似形式(相同 class),运行 在同一个 UI 线程中,包含一个按钮,并且在按钮的 Click-Event,调用了一个服务方法。在服务方法内部,有日志记录调用。在日志消息中,我想要一个 属性 包含按钮在哪个表单实例中的信息被点击了)。

我不想修改所有的记录调用。 Web 中有关日志上下文/NDC 的示例都只讨论多个客户端/asp.net 请求等,而不是 1 个线程中的多个表单。

谢谢, 蒂姆

为此,请将表单的 Activated 事件中的属性设置为您要记录的内容:

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

在您的日志记录配置中,您可以为每个附加程序引用 PatternLayout 中的属性:

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

编辑:要保留多个值,请使用堆栈,如本单元测试中输出的那样:

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