间歇性的log4net RollingFileAppender文件锁问题

120
我们在开发和生产环境中遇到一个间歇性的问题,就是我们的日志文件没有被记录下来。 当在Visual Studio中运行调试时,我们会在VS输出窗口中看到以下log4net错误消息。
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>

正如提到的那样,我们在机器上偶尔会看到这个问题,但一旦出现问题,它就会持续存在。

3个回答

181

尝试在您的<appender />元素中添加

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

这会有一些性能影响,因为这意味着log4net将锁定文件,写入文件并在每次写操作后解锁文件(与默认行为相反,后者会获取并长时间保持锁定状态)。

默认行为的一个含义是,如果您正在多个工作进程下运行同一台机器上的Web站点,则每个工作进程都会尝试无限期地获取和保持该锁定状态,并且其中两个进程将会失败。将锁定模型更改为最小锁可以解决此问题。

(调试时,不优雅的终止和大量新的工作进程启动通常会发生)。

祝好运!


1
这让我省了很多时间去想为什么我的记录器会间歇性地工作。我向应用程序池添加了工作进程,呃! - RhinoDevX64
我正在一个服务中使用它,除了这个更改之外,运行服务的用户还需要写入权限。谢谢! - LowTide
3
我只想读取文件,但log4net也会锁定读取...它可以只为写入而锁定并进行共享读取。 - JobaDiniz

42
请注意 log4net FAQ

如何让多个进程记录到同一个文件?

在尝试任何替代方案之前,您应该问自己是否真的需要让多个进程记录到同一个文件,如果不需要,请不要这样做 ;-).

FileAppender为此用例提供可插拔锁定模型,但所有现有实现都存在问题和缺陷。

默认情况下,FileAppender在记录日志时会对日志文件持有独占写锁。这会防止其他进程向该文件写入。众所周知,在某些版本的Linux上使用Mono时,此模型会崩溃,并且当另一个进程尝试访问日志文件时,日志文件可能会损坏。

MinimalLock仅在记录日志时获取写锁。这允许多个进程交错地写入同一个文件,但性能会大幅降低。

InterProcessLock根本不锁定文件,而是使用系统范围的Mutex进行同步。只有所有进程共同合作(并且使用相同的锁定模型),才能使其正常工作。每次要写入日志条目时获取和释放Mutex将导致性能下降,但是相对于使用MinimalLock,使用Mutex更可取。

如果您使用RollingFileAppender,情况会变得更糟,因为几个进程可能会尝试同时启动滚动日志文件。当滚动文件时,RollingFileAppender完全忽略锁定模型,无法与此场景兼容。

更好的选择是让您的进程记录到RemotingAppenders。使用RemoteLoggingServerPlugin(或IRemoteLoggingSink),进程可以接收所有事件并将它们记录到单个日志文件中。其中一个示例展示了如何使用RemoteLoggingServerPlugin。


8
如果您有
<staticLogFileName value="true" />
<rollingStyle value="Date" />
<datePattern value="yyyyMMdd" />

并添加

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

在滚动发生时,可能会出现错误。 第一个进程将创建新文件并重命名当前文件。 然后下一个进程将执行相同的操作,并获取新创建的文件并覆盖新重命名的文件。 导致昨天的日志文件为空。


1
只有在多个进程访问同一滚动文件时,这才是正确的。在同一进程中是安全的。http://hectorcorrea.com/blog/log4net-thread-safe-but-not-process-safe - Mike Chamberlain
根据OP的评论(请参见他对答案的评论),将有多个工作人员同时工作,使用log4net进行日志记录。因此,这个问题是相关的! - seebiscuit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接