C# 在Log4Net中的AdoNetAppender中使用缓冲区进行惰性计算

C# 在Log4Net中的AdoNetAppender中使用缓冲区进行惰性计算,c#,buffer,log4net,adonetappender,C#,Buffer,Log4net,Adonetappender,我正在使用Log4Net自定义属性将一些环境信息添加到日志中。我创建了一个具有全局可访问属性的实用程序类,我的程序类使用这些属性来存储上下文信息(订单id、用户id等),并在它们周围创建了一个惰性包装器,因此我不需要一直更改Log4Net ThreadContext。大概是这样的: public class LoggerPropertyProvider { private readonly string _value; public LoggerPropertyProvider

我正在使用Log4Net自定义属性将一些环境信息添加到日志中。我创建了一个具有全局可访问属性的实用程序类,我的程序类使用这些属性来存储上下文信息(订单id、用户id等),并在它们周围创建了一个惰性包装器,因此我不需要一直更改Log4Net ThreadContext。大概是这样的:

public class LoggerPropertyProvider
{
    private readonly string _value;

    public LoggerPropertyProvider(string value)
    {
        _value = value;
    }

    public override string ToString()
    {
        return _value;
    }
}
无论我想将什么值作为属性公开给Log4Net,我只需在应用程序开始时使用这个惰性计算器注册即可

ThreadContext.Properties["ORDER_ID"] = new LoggerPropertyProvider(ContextInformation.OrderId);
对于无缓冲区的附加器(如滚动文件)或在AdoNetAppender中将缓冲区设置为0时,它可以正常工作。但是,当我有buffer>1Log4Net时,会延迟对属性的评估,直到应用程序结束时刷新缓冲区,或者当buffer>bufferSize
中的条目时

当这种情况发生时,信息不再在全局属性中,或者它的值已更改(如循环处理顺序),因此我在日志中得到错误或空值

我能看到的唯一解决方法是停止使用缓冲区,以便在刷新条目时在所有调用中计算属性值。由于ThreadContext中的属性仅在刷新缓冲区时才进行计算,因此恐怕无法为每个日志调用提供不同的属性值

在缓冲条目而不是刷新条目时,是否有任何方法可以让Log4Net评估ThreadContext(或它拥有的其他上下文)


谢谢

您似乎必须将该属性置于log4net线程上下文中:

log4net.ThreadContext.Properties["ORDER_ID"] = new LoggerPropertyProvider(ContextInformation.OrderId);
此上下文覆盖全局上下文中的任何属性,并由log4net it self管理:


默认情况下,log4net不会在日志时为缓冲的附加器从上下文中提供属性值。它们在缓冲区刷新时得到评估

要解决这个问题,您必须从log4net.Core名称空间实现必需的

public class LoggerPropertyProvider : IFixingRequired
{
    private readonly string _value;

    public LoggerPropertyProvider(string value)
    {
        _value = value;
    }

    public override string ToString()
    {
        return _value;
    }

    object IFixingRequired.GetFixedObject()
    {
        return ToString();
    }
}
(使用我自己的属性提供程序进行测试,由于我自己的需要,它依赖于http上下文:

// We can not use log4net ThreadContext or LogicalThreadContext with asp.net, since
// asp.net may switch thread while serving a request, and reset the call context in
// the process.
public class HttpContextValueProvider : IFixingRequired
{
    private string _contextKey;
    public HttpContextValueProvider(string contextKey)
    {
        _contextKey = contextKey;
    }

    public override string ToString()
    {
        var currContext = HttpContext.Current;
        if (currContext == null)
            return null;
        var value = currContext.Items[_contextKey];
        if (value == null)
            return null;
        return value.ToString();
    }

    object IFixingRequired.GetFixedObject()
    {
        return ToString();
    }
}
总的想法来自于。请看下面的问题 如果您想了解有关此
HttpContextValueProvider
的更多最新详细信息