Log4net 缓冲区不起作用

Log4net buffer doesn't work

我正在将 log4net 与 log4net.Elasticsearch 插件一起使用(这应该无关紧要,问题是关于 log4net 缓冲的一般情况)并且我正在尝试使用 buffer。我不希望每个日志事件都单独发送到 Elasticsearch。这是我的 appender 配置:

<appender name="ElasticSearchAppender" type="log4net.ElasticSearch.ElasticSearchAppender, log4net.ElasticSearch">
    <layout type="log4net.Layout.PatternLayout,log4net">
      <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p %c{1}:%L - %m%n" />
    </layout>
    <connectionString value="Server=xxx.xxx.xxx.xxx;Index=api_actions_log;Port=9200"/>
    <lossy value="false" />
    <bufferSize value="100" />
    <evaluator type="log4net.Core.LevelEvaluator">
        <threshold value="INFO"/>
    </evaluator>
    <filter type="log4net.Filter.LoggerMatchFilter">
          <loggerToMatch value="My.Namespace.LoggingFilterAttribute" />
    </filter>
    <filter type="log4net.Filter.DenyAllFilter" />
</appender>

如您所见,我指定了 bufferSize=100,但即使是每条消息都会立即发送到 Elasticsearch。

我正在深入研究并试图找出代码中真正发生的事情。当 Log 方法被调用到 ES appender class 上的 Append 方法时。方法继承自基本 log4net BufferingAppenderSkeleton,如下所示:

protected override void Append(LoggingEvent loggingEvent)
{
  if (this.m_cb == null || this.m_bufferSize <= 1)
  {
    if (this.m_lossy && (this.m_evaluator == null || !this.m_evaluator.IsTriggeringEvent(loggingEvent)) && (this.m_lossyEvaluator == null || !this.m_lossyEvaluator.IsTriggeringEvent(loggingEvent)))
      return;
    if (this.m_eventMustBeFixed)
      loggingEvent.Fix = this.Fix;
    this.SendBuffer(new LoggingEvent[1]
    {
      loggingEvent
    });
  }
  else
  {
    loggingEvent.Fix = this.Fix;
    LoggingEvent loggingEvent1 = this.m_cb.Append(loggingEvent);
    if (loggingEvent1 != null)
    {
      if (!this.m_lossy)
      {
        this.SendFromBuffer(loggingEvent1, this.m_cb);
      }
      else
      {
        if (this.m_lossyEvaluator == null || !this.m_lossyEvaluator.IsTriggeringEvent(loggingEvent1))
          loggingEvent1 = (LoggingEvent) null;
        if (this.m_evaluator != null && this.m_evaluator.IsTriggeringEvent(loggingEvent))
          this.SendFromBuffer(loggingEvent1, this.m_cb);
        else if (loggingEvent1 != null)
          this.SendBuffer(new LoggingEvent[1]
          {
            loggingEvent1
          });
      }
    }
    else if (this.m_evaluator != null && this.m_evaluator.IsTriggeringEvent(loggingEvent))
      this.SendFromBuffer((LoggingEvent) null, this.m_cb);
  }
}

在方法的开头,它首先检查我们是否使用缓冲区。答案是肯定的,所以它进入外部 If 的 else 块。然后它将事件添加到缓冲区并检查是否已从缓冲区返回任何事件:

    LoggingEvent loggingEvent1 = this.m_cb.Append(loggingEvent);
    if (loggingEvent1 != null)

If 被评估为 false 所以代码继续 else if:

    else if (this.m_evaluator != null && this.m_evaluator.IsTriggeringEvent(loggingEvent))
      this.SendFromBuffer((LoggingEvent) null, this.m_cb);

条件被评估为真,因为我的 log4net 配置中有评估器(级别评估器)并且消息处于适当的级别。 SendFromBuffer 方法立即将消息发送到存储(在我的例子中是 Elasticsearch)。

分解成 log4net 代码后,我不明白缓冲是如何工作的,也不知道我需要设置什么。在我看来,总会有一些评估器(至少是级别评估器),因此将始终调用 SendFromBuffer 方法,导致每条消息分别发送到存储。我想知道如何设置 log4net 以真正使用缓冲区。

log4net 正在运行 as documented:评估者 属性 "gets or sets the ITriggeringEventEvaluator that causes the buffer to be sent immediately."

来自this explanation

The Evaluator is a pluggable object that is used by the BufferingAppenderSkeleton to determine if a logging event should not be buffered, but instead written/sent immediately. If the Evaluator decides that the event is important then the whole contents of the current buffer will be sent along with the event.

Typically an SmtpAppender will be setup to buffer events before sending as the cost of sending an email may be relatively high. If an important event arrives, say an ERROR, we would like this to be delivered immediately rather than waiting for the buffer to become full. This is where the Evaluator comes in as it allows us to say: "when an important event arrives don't worry about buffering, just send over everything you have right now".

因此,每条具有 Info 或更高日志爱的消息都会触发您的 LevelEvaluator 并导致发送缓冲区。