Производительность Log4Net - PullRequest
16 голосов
/ 09 марта 2010

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

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

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

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

Вот пример моего файла конфигурации 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));

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

Буду признателен за любые советы, как улучшить это.

Ответы [ 3 ]

31 голосов
/ 09 марта 2010

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

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

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

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

4 голосов
/ 09 марта 2010

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

У Питера Лиллевольда есть хорошее предложение по настройке 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>
0 голосов
/ 09 марта 2010

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

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

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

...