Периодическая проблема с заблокированным файлом log4net RollingFileAppender

113

Мы наблюдаем периодическую проблему на машинах разработки и производства, из-за которой наши файлы журналов не регистрируются.

При запуске в разработке и отладке с использованием Visual Studio мы получаем следующие сообщения об ошибках log4net в окне вывода VS:

log4net:ERROR [RollingFileAppender] Unable to acquire lock on file C:\folder\file.log.

Процесс не может получить доступ к файлу C: \ folder \ file.log, поскольку он используется другим процессом.

log4net:ERROR XmlConfigurator: Failed to find configuration section 'log4net' in the application's .config file.
Check your .config file for the <log4net> and <configSections> elements.

Раздел конфигурации должен выглядеть так:

<section
  name="log4net"
  type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />

Наш текущий способ решения проблемы - переименовать последний файл журнала. Мы, конечно, ожидаем, что это не удастся (из-за вышеупомянутой блокировки файла), но обычно этого не происходит. Один или два раза переименование не удавалось из-за блокировки процесса aspnet_wp.exe .

Наш раздел конфигурации log4net показан ниже:

<log4net>
  <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
    <file value="C:\folder\file.log"/>
    <appendToFile value="true" />
    <datePattern value="yyyyMMdd" />
    <rollingStyle value="Date" />
    <maximumFileSize value="10MB" />
    <maxSizeRollBackups value="100" />
    <layout type="log4net.Layout.PatternLayout">
      <header value="[Header]&#xA;"/>
      <footer value="[Footer]&#xA;"/>
      <conversionPattern value="%date %-5level %logger ${COMPUTERNAME} %property{UserHostAddress} [%property{SessionID}] - %message%newline"/>
    </layout>
  </appender>
  <root>
    <level value="INFO"/>
    <appender-ref ref="RollingLogFileAppender"/>
  </root>
</log4net>

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

Ричард Ив
источник

Ответы:

172

Попробуйте добавить

<lockModel type = "log4net.Appender.FileAppender + MinimalLock" />

к вашей <appender />стихии. Существует некоторое влияние на производительность, потому что это означает, что log4net будет блокировать файл, записывать в него и разблокировать его для каждой операции записи (в отличие от поведения по умолчанию, при котором блокировка устанавливается и удерживается в течение длительного времени).

Одно из следствий поведения по умолчанию заключается в том, что если вы используете его на веб-сайте, который выполняется несколькими рабочими процессами, запущенными на одном компьютере, каждый из них будет пытаться получить и удерживать эту блокировку на неопределенный срок, а два из них - просто проиграю. Изменение модели блокировки на минимальную блокировку позволяет обойти эту проблему.

(При отладке некорректное завершение работы и запуск множества новых рабочих процессов - это именно то, что может произойти.)

Удачи!

Николай Пясецкий
источник
Избавило меня от многих головокружений о том, почему мой регистратор работал с перебоями. Я добавил рабочие процессы в пул приложений, да!
RhinoDevX64
Я использую это в службе, и в дополнение к этому изменению пользователь, выполняющий службу, также имел необходимое разрешение на запись. Спасибо!
LowTide
Большое спасибо, сэкономили много времени.
Siva
2
Я просто хотел бы прочитать файл, но log4net также блокирует чтение ... он может блокироваться только для записи и совместного чтения
JobaDiniz
37

Также обратите внимание на часто задаваемые вопросы о log4net :

Как заставить несколько процессов регистрироваться в одном файле?

Прежде чем вы даже начнете пробовать любую из предложенных альтернатив, спросите себя, действительно ли вам нужно, чтобы несколько процессов регистрировались в одном файле, а затем не делайте этого ;-).

FileAppender предлагает подключаемые модели блокировки для этого варианта использования, но все существующие реализации имеют проблемы и недостатки.

По умолчанию FileAppender удерживает исключительную блокировку записи в файл журнала во время его ведения. Это предотвращает запись в файл другими процессами. Эта модель, как известно, не работает (по крайней мере, в некоторых версиях) Mono в Linux, и файлы журнала могут быть повреждены, как только другой процесс попытается получить доступ к файлу журнала.

MinimalLock получает блокировку записи только во время записи журнала. Это позволяет нескольким процессам чередовать записи в один и тот же файл, хотя и со значительной потерей производительности.

InterProcessLock вообще не блокирует файл, а синхронизирует его с помощью общесистемного Mutex. Это будет работать, только если все процессы взаимодействуют (и используют одну и ту же модель блокировки). Получение и освобождение Mutex для каждой записи журнала, которая должна быть записана, приведет к потере производительности, но Mutex предпочтительнее использования MinimalLock.

Если вы используете RollingFileAppender, ситуация становится еще хуже, так как несколько процессов могут попытаться запустить одновременную прокрутку файла журнала. RollingFileAppender полностью игнорирует модель блокировки при прокрутке файлов, прокрутка файлов просто несовместима с этим сценарием.

Лучшая альтернатива - вести журнал процессов в RemotingAppenders. Используя RemoteLoggingServerPlugin (или IRemoteLoggingSink), процесс может получать все события и записывать их в один файл журнала. Один из примеров показывает, как использовать RemoteLoggingServerPlugin.

Чиприан Тейосану
источник
6

Если у вас есть

<staticLogFileName value="true" />
<rollingStyle value="Date" />
<datePattern value="yyyyMMdd" />

и добавить

<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />

тогда при раскрутке будет ошибка. Первый процесс создаст новый файл и переименует текущий файл. Затем следующий процесс сделает то же самое и возьмет вновь созданный файл и перезапишет только что переименованный файл. В результате логфил за последний день пуст.

Jonte
источник
1
Это верно только в том случае, если несколько процессов обращаются к одному и тому же скользящему файлу. Это безопасно в рамках того же процесса. hectorcorrea.com/blog/log4net-thread-safe-but-not-process-safe
Майк Чемберлен
@MikeChamberlain Согласно OP (см. Его комментарий для ответа) одновременно будет работать несколько рабочих, использующих log4net для ведения журнала. Поэтому этот вопрос актуален!
seebiscuit