我们正在使用Log4net的ThreadContext.Stacks,并且大多数情况下运行良好。我的问题是,如果有多个ThreadContext.Stacks [“key”]。Push(...)。

使用简单的ConversionPattern:

<param name="ConversionPattern value="... topProp=%properties{key} ..."/>

我看到如下日志条目:
... topProp=first second third ...

我真的很想只查看最近推送的值,而不是所有值。我曾希望可以在appender / layout / ConversionPattern中输入以下内容:
<param name="ConversionPattern value="... topProp=%properties{key}{1} ..."/>

但这不起作用。我可以通过假设/要求所有值都具有相同的长度(例如5)并执行以下操作来弄混它:
<param name="ConversionPattern value="... topProp=%5.5properties{key} ..."/>

但这并不是真正的吸引力。有任何想法吗?

谢谢!

[编辑添加非常简单的示例]
using System;
using System.IO;
using log4net;
using log4net.Config;

namespace ThreadLocalExample {
class Program {
    private const string PropJobId = "Example:JobId";

    static void Main() {
        XmlConfigurator.Configure(new FileInfo("log4net.cfg"));
        var log = LogManager.GetLogger(typeof(Program));

        ThreadContext.Stacks[PropJobId].Push("Old");

        log.Debug("Enter using");
        using (ThreadContext.Stacks[PropJobId].Push("New")) {
            log.Debug("stuff");
        }
        log.Debug("Out of using");

        log.Debug("done.");
        Console.ReadKey();
    }
  }
}

使用log4net配置:
<appender name="Console" type="log4net.Appender.ConsoleAppender">
    <threshold value="ALL" />
    <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="[jobId=%P{Example:JobId}]: %m%n" />
    </layout>
</appender>

产生:
[jobId=Old]: Enter using
[jobId=Old New]: stuff
[jobId=Old]: Out of using
[jobId=Old]: done.

但我想:
[jobId=Old]: Enter using
[jobId=New]: stuff
[jobId=Old]: Out of using
[jobId=Old]: done.

最佳答案

我遇到了同样的问题,这不仅与“格式错误”有关,因为我使用了期望整数的数据库附加程序(AdoNetAppender)。因此,在将所有堆叠的值连接在一起之后,结果不再是整数。考虑这样的追加器:

<appender name="DbAppender" type="log4net.Appender.AdoNetAppender">
...
<commandText value="INSERT INTO Log ([Id]) VALUES (@Id)" />
<parameter>
    <parameterName value="@Id" />
    <dbType value="Int32" />
    <layout type="log4net.Layout.PatternLayout" value="%P{someId}" />
</parameter>

此追加程序将不接受任何日志消息,其中“someId”被堆叠两次或多次-数据库中没有日志...

因此,为了解决此问题,我放弃了堆栈,转而使用平面属性。
我已经编码了一些简短的扩展名:
    public static class Log4NetExt {
        public static IDisposable ThreadContextPush(string key, object value) {
            object oldVal = ThreadContext.Properties[key];
            ThreadContext.Properties[key] = value;
            var topMostCleaner = new DispCleaner();
            topMostCleaner.EvDispose += () => {
                // Pop = restore old value
                ThreadContext.Properties[key] = oldVal;
            };
            return topMostCleaner;
        }

        private class DispCleaner : IDisposable {
            public event Action EvDispose;

            public void Dispose() {
                if (EvDispose != null) EvDispose();
            }
        }
    }

现在,代替:
using (ThreadContext.Stacks[PropJobId].Push("New")) {

写:
using (Log4NetExt.ThreadContextPush(PropJobId, "New")) {

它可以正常工作;)

(这段简短的代码并未遵循构建一次性对象,删除事件处理程序和所有这些东西的所有最佳做法,但是它很简短,我认为在这种简单情况下是安全的)。

关于log4net - 仅记录最顶层的ThreadContext堆栈项,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31256955/

10-11 15:52