简体   繁体   English

在Log4Net中使用AdoNetAppender中的缓冲区进行延迟评估

[英]Lazy evaluation with buffers in AdoNetAppender in Log4Net

I'm using Log4Net custom properties to add some environmental information into my logs. 我正在使用Log4Net自定义属性将一些环境信息添加到我的日志中。 I created an utility class with global accessible properties that my program classes use to store context information (order id, user id, etc) and a lazy wrapper around them so I don't need to change Log4Net ThreadContext all the time. 我创建了一个具有全局可访问属性的实用程序类,我的程序类使用它们来存储上下文信息(订单ID,用户ID等),并在它们周围进行惰性包装,因此无需始终更改Log4Net ThreadContext。 Something like this: 像这样:

public class LoggerPropertyProvider
{
    private readonly string _value;

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

    public override string ToString()
    {
        return _value;
    }
}

Whatever value I want to expose as a property to Log4Net I just register using this lazy evaluator at the start of the application. 我想将其作为Log4Net的属性公开的任何值,我都只是在应用程序开始时使用此惰性评估器进行注册。

ThreadContext.Properties["ORDER_ID"] = new LoggerPropertyProvider(ContextInformation.OrderId);

It works just fine with buffer-less appenders (such as rolling file) or when the buffer is set to 0 in AdoNetAppender. 它适用于无缓冲区追加器 (例如滚动文件),或者在AdoNetAppender中将缓冲区设置为0时也可以正常工作。 However, when I have buffer > 1 Log4Net defers the evaluation of the property until the buffer is flushed at the end of the application or when entries in buffer > bufferSize . 但是,当我的buffer> 1时, Log4Net会推迟对属性的评估,直到在应用程序结束时刷新缓冲区或在buffer> bufferSize中的条目被刷新为止。

When this happens the information is not in the global property anymore or it's value has been changed (like a loop processing orders) so I get a wrong or null value in my logs. 发生这种情况时,信息不再位于global属性中,或者其值已更改(例如循环处理订单),因此我在日志中得到了错误或空值。

The only option I can see to fix this is stop using buffers so the property value is evaluated in all calls when the entry is being flushed. 我可以看到解决此问题的唯一方法是停止使用缓冲区,以便在刷新条目时在所有调用中评估属性值。 Since the properties in ThreadContext are only evaluated when the buffer is being flushed I'm afraid I cannot have a different property value for each log call. 由于仅在刷新缓冲区时才评估ThreadContext中的属性,所以我恐怕无法为每个日志调用使用不同的属性值。

Is there any way I can make Log4Net evaluate a ThreadContext (or some other context it has) when buffering the entry instead of when it flushes it? 有什么方法可以使Log4Net在缓冲条目而不是刷新条目时评估ThreadContext(或它具有的其他上下文)?

Thanks 谢谢

By default, log4net does not fix property provider values from contexts at log time for buffered appenders. 默认情况下,log4net不会在日志时为缓冲的附加fix上下文中的属性提供程序值。 They get evaluated at buffer flush time. 它们在缓冲区刷新时得到评估。

To solve this issue, you have to implement IFixingRequired from log4net.Core namespace. 要解决此问题,必须从log4net.Core命名空间实现IFixingRequired。

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

(Tested with my own property provider, which relies on http context due to my own needs: (通过我自己的属性提供程序进行了测试,由于我自己的需要,该提供程序依赖于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();
    }
}

General idea coming from piers blog . 总的想法来自码头博客 See this my other answer to another question if you'd like more up to date details about this HttpContextValueProvider .) 如果您想要有关此HttpContextValueProvider更多最新详细信息,请参阅我的另一个问题的答案 。)

It seems you do have to put the property in the log4net thread context: 看来您必须将属性放在log4net线程上下文中:

log4net.ThreadContext.Properties["ORDER_ID"] = new LoggerPropertyProvider(ContextInformation.OrderId);

This context overrides any properties in the global context and is managed by log4net it self: 此上下文覆盖全局上下文中的所有属性,并由log4net自行管理:

log4net.ThreadContext log4net.ThreadContext

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM