Я использую log4net вместе с плагином log4net.Elasticsearch (это не имеет значения, вопрос касается буферизации log4net в целом), и я пытаюсь использовать буфер. Я не хочу, чтобы каждое событие журнала отправлялось в 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.
Я копался и пытался выяснить, что на самом деле происходит в коде. Когда вызывается метод журнала, он переходит к методу добавления в классе приложения ES. Метод унаследован от базового 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);
}
}
В начале метода он сначала проверяет, используем ли мы буфер. Ответ - да, поэтому он переходит в блок else внешнего If. Затем он добавляет событие в буфер и проверяет, было ли какое-либо событие возвращено из буфера:
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 для реального использования буфера.