Подтвердить что ты не робот

Как создать асинхронную оболочку для log4net?

По умолчанию log4net является синхронным механизмом ведения журнала, и мне было интересно, есть ли способ иметь асинхронное ведение журнала с помощью log4net?

4b9b3361

Ответ 1

Если вы перейдете на сайт log4net, вы можете найти несколько примеров, по крайней мере один из которых является асинхронным Appender.

http://logging.apache.org/log4net/release/example-apps.html

Обратите внимание, что я не использовал ни один из этих примеров, поэтому я не могу ручаться за них так или иначе.

Вот ссылка на фактический асинхронный appender из области примеров log4net в репозитории кода:

http://svn.apache.org/viewvc/logging/log4net/trunk/examples/net/2.0/Appenders/SampleAppendersApp/cs/src/Appender/AsyncAppender.cs?view=markup

Я посмотрел на него кратко и, по-видимому, выступал в качестве обертки вокруг одного или нескольких "обычных" Appenders. В каждом запросе на ведение журнала (содержащий один или несколько объектов LoggingEvent) поток ThreadPool используется для пересылки LoggingEvents в список обернутых Appenders.

Ответ 2

Просто хотел предоставить мое полное решение для справки. Пара важных элементов, FixFlags позволяет вам фиксировать поток, который фактически выполняет регистрацию. Блокирующая коллекция находится в ReactiveExtensions. Суть здесь заключается в том, что ваш приставщик пересылки обрабатывает асинхронный материал, а затем просто пересылает на LoggingEvent стандартное приложение Log4Net, которое позволяет Log4Net делать все, что ему хорошо. Не изобретать колесо.

/// <summary>
/// Provides an extension for the log4net libraries to provide ansynchronous logging capabilities to the log4net architecture
/// </summary>
public class AsyncLogFileAppender : log4net.Appender.ForwardingAppender
{
    private static int _asyncLogFileAppenderCount = 0;
    private readonly Thread _loggingThread;
    private readonly BlockingCollection<log4net.Core.LoggingEvent> _logEvents = new BlockingCollection<log4net.Core.LoggingEvent>();

    protected override void Append(log4net.Core.LoggingEvent loggingEvent)
    {
        loggingEvent.Fix = FixFlags.ThreadName;
        _logEvents.Add(loggingEvent);
    }

    public AsyncLogFileAppender()
    {

        _loggingThread = new Thread(LogThreadMethod) { IsBackground = true, Name = "AsyncLogFileAppender-" + Interlocked.Increment(ref _asyncLogFileAppenderCount), };
        _loggingThread.Start();
    }

    private void LogThreadMethod()
    {
        while (true)
        {
            LoggingEvent le = _logEvents.Take();
            foreach (var appender in Appenders)
            {
                appender.DoAppend(le);
            }
        }
    }
}

Затем в вашем файле log4net.xml вы устанавливаете appenders таким образом

<!-- Standard form output target location and form -->
<appender name="StandardAppender" type="TSUIC.Logging.AsyncLogFileAppender">
<appender-ref ref="StandardAppenderSync" />
</appender>

<appender name="StandardAppenderSync" type="log4net.Appender.RollingFileAppender">
    <!-- The standard pattern layout to use -->
    <file value="log\Log_" />
    <appendToFile value="true" />
    <rollingStyle value="Date" />
    <maxSizeRollBackups value="-1" />
    <maximumFileSize value="5GB" />
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    <staticLogFileName value="false" />
    <datePattern value="yyyyMMdd'.txt'" />
    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
    </layout>
</appender>

Update:

Если вы хотите использовать контекст в log4net как "log4net.ThreadContext.Properties["CustomColumn"]"

Затем вам нужно обновить код выше, например

loggingEvent.Fix = FixFlags.All;

Ответ 3

Вот как я это делаю:

Task.Factory.StartNew(() => log.Info("My Info"));

Таким образом, log4net выполняет ведение журнала в отдельном потоке, асинхронно...

BTW, Task класс находится в пространстве имен System.Threading.Tasks.

Ответ 4

Некоторые из идей здесь неверны и приводят к недействительным/устаревшим данным, выходу из строя или очень плохой производительности. Например, в принятом ответе предлагается использовать log4net AsyncAppender, который использует ThreadPool, что приводит к ошибкам, которые не могут быть проблемой для некоторых, но я, конечно, хочу, чтобы мои события журнала были один за другим, он также может иметь ужасную производительность и слишком сильно надавливать на ThreadPool, и он не загружает записи журнала. Ответ, предложенный Джонатаном, безусловно, является гораздо лучшим решением, но по-прежнему не имеет оптимальной производительности.

Хороший пример того, как это должно быть реализовано, можно найти ЗДЕСЬ и результаты сравнительного анализа и объяснение ЗДЕСЬ.

Еще одна хорошая особенность этого решения заключается в том, что он был реализован как Forwarder not a Appender, позволяющий пользователю включать более одного Appender и одновременно регистрировать каждый из них.

Ответ 5

Я столкнулся с этой проблемой на этой неделе, однако я не хотел, чтобы увольнять запросы в пул потоков, потому что это может закончиться голодающим остальным приложением потоков, поэтому я придумал приложение Asyncronous, которое запускает выделенный поток для добавления, которое подается через буфер. Посмотрите здесь: http://cjbhaines.wordpress.com/2012/02/13/asynchronous-log4net-appenders/