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

Производительность Log4Net

Я написал приложение С#, которое работает постоянно в цикле, и несколько потоков записывают в файл log4net.

Проблема в том, что чем дольше приложение работает, тем больше времени требуется для завершения цикла. Я запустил профилировщик ANTS Performance и заметил, что большая часть этого времени процессора тратится на журнал с log4.net.

Чем больше подробных журналов, тем больше процессор он использует, и через 30 минут он использует 100% процессора. Если отключить регистрацию, время, затраченное на цикл, остается постоянным с течением времени. Я посмотрел на Windows Performance Monitor, а физический диск - в большинстве случаев IDLE.

Я пытался свести мой журнал к минимуму, но даже при относительно небольшом количестве протоколирования я все еще испытываю проблему.

Вот пример файла конфигурации Log4net.xml:

<log4net>
  <root>
    <!-- Levels: OFF, DEBUG, INFO, WARN, ERROR, FATAL-->
    <level value="INFO" />
    <appender-ref ref="RollingLogFileAppender" />
  </root>

  <!--Logs to a file-->
  <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
    <file value="c:\\logs\\log-file.txt" />
    <appendToFile value="true" />
    <lockingModel type="log4net.Appender.FileAppender+ExclusiveLock" />
    <rollingStyle value="Composite" />
    <datePattern value="yyyyMMdd" />
    <maxSizeRollBackups value="20" />
    <maximumFileSize value="1MB" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger %L %M Schdl:[%property{scheduleContext}] Job:[%property{jobContext}] - %message%newline" />
    </layout>
  </appender>
</log4net>

Я использую один и тот же журнал из каждого объекта, который регистрируется.

  log4net.ILog logger;
  log4net.Config.BasicConfigurator.Configure();
  logger = log4net.LogManager.GetLogger(typeof(myProject));

Зачем использовать больше и больше процессора, чем дольше он работает?

Любые рекомендации относительно того, как улучшить это, будут оценены.

4b9b3361

Ответ 1

Вы настраиваете log4net в каждом объекте, который регистрируется? Это похоже на ваш код. Конфигурирование должно выполняться один раз в процессе, например. при запуске, а затем ваши объекты должны получить только логгер.

Для каждого класса, который должен регистрироваться, я обычно имею следующий шаблон:

class SomeClass
{
    private static readonly ILog log = LogManager.GetLogger(typeof(SomeClass));
    ...
}

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

Ответ 2

Что вы делаете с этими свойствами контекста? Schdl:[%property{scheduleContext}] Job:[%property{jobContext}] Если вы назначаете нечто большее, чем просто значение здесь (или объект с простым методом ToString()), он может привести к снижению производительности. См. Руководство по log4net в Активные значения свойств для представления о том, о чем я говорю.

Peter Lillevold имеет хорошее предложение о настройке log4net только один раз. Вы также можете поместить следующую строку в файл AssemblyInfo.cs:

[assembly: log4net.Config.XmlConfigurator()]

Следующая строка легко вырезать и вставлять в любой класс, который регистрирует:

private static readonly log4net.ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

Вы также можете попробовать включить внутреннюю регистрацию log4net, чтобы узнать, что происходит:

<appSettings>
  <add key="log4net.Internal.Debug" value="true"/>
</appSettings>

Ответ 3

(Я никогда не использовал log4net, прежде чем принимать то, что я рекомендую с осторожностью)

Вы можете написать прокси-сервер async для компонента log4Net и войти в выделенный поток. Вы больше не будете блокировать свои основные потоки с попытками записать в файл журнала.

Это бесполезно, если в log4net уже есть асинхронный прокси.