间歇性 log4net RollingFileAppender 锁定文件问题

Posted

技术标签:

【中文标题】间歇性 log4net RollingFileAppender 锁定文件问题【英文标题】:Intermittent log4net RollingFileAppender locked file issue 【发布时间】:2011-01-01 05:54:16 【问题描述】:

我们在开发和生产机器上看到一个间歇性问题,导致我们的日志文件没有被记录到。

在使用 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 %propertyUserHostAddress [%propertySessionID] - %message%newline"/>
    </layout>
  </appender>
  <root>
    <level value="INFO"/>
    <appender-ref ref="RollingLogFileAppender"/>
  </root>
</log4net>

如前所述,我们偶尔会在机器上看到此问题,但一旦问题发生,它就会持续存在。

【问题讨论】:

【参考方案1】:

尝试添加

到您的&lt;appender /&gt; 元素。存在一些性能影响,因为这意味着 log4net 将锁定文件,写入文件,然后为每个写入操作解锁(与默认行为相反,它会长时间获取并保持锁定)。

默认行为的一个含义是,如果您在一个网站上使用它,而该网站在同一台机器上运行的多个工作进程下执行,每个工作进程都会尝试无限期地获取并持有该锁,并且两个他们中的一些人只会输。将锁定模型更改为最小锁定可以解决此问题。

(在调试时,不正常的终止和启动大量新的工作进程正是可能发生的事情。)

祝你好运!

【讨论】:

为我的记录器间歇性工作的原因节省了很多时间。我在应用程序池中添加了工作进程,呵呵! 我在一个服务中使用它,除了这个变化之外,用户运行该服务也需要写入权限。谢谢! 我只想读取文件,但是 log4net 也锁定读取...它可以锁定仅用于写入和共享读取【参考方案2】:

还要注意log4net FAQ:

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

在您开始尝试提供的任何替代方案之前,请先询问 你自己是否真的需要让多个进程登录到 相同的文件,然后不要这样做;-)。

FileAppender 为这个用例提供了可插入的锁定模型,但所有 现有的实现存在问题和缺点。

默认情况下,FileAppender 在日志上持有排他写锁 记录时的文件。这可以防止其他进程写入 到文件。众所周知,这种模型会因(至少在某些 Linux 上的 Mono 版本和日志文件可能会立即损坏 另一个进程尝试访问日志文件。

MinimalLock 仅在写入日志时获取写入锁。 这允许多个进程交错写入同一个文件, 尽管性能损失很大。

InterProcessLock 根本不锁定文件,而是使用 系统范围的互斥锁。这只有在所有进程合作时才有效(并且 使用相同的锁定模型)。获取和释放 Mutex 对于要写入的每个日志条目,都会导致丢失 性能,但互斥锁比使用 MinimalLock 更可取。

如果你使用 RollingFileAppender,事情会变得更糟,因为几个 进程可能会尝试同时开始滚动日志文件。 RollingFileAppender 滚动时完全忽略锁定模型 文件,滚动文件根本不兼容这种情况。

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

【讨论】:

【参考方案3】:

如果你有

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

并添加

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

然后滚动发生时会出错。 第一个过程将创建新文件并重命名当前文件。 然后下一个过程将执行相同的操作并获取新创建的文件并覆盖新重命名的文件。 导致最后一天的日志字段为空。

【讨论】:

只有当多个进程访问同一个滚动文件时才适用。在同一过程中是安全的。 hectorcorrea.com/blog/log4net-thread-safe-but-not-process-safe @MikeChamberlain 根据 OP(请参阅他的评论回答)将有多个工人同时工作,使用 log4net 记录。因此这个问题是相关的!

以上是关于间歇性 log4net RollingFileAppender 锁定文件问题的主要内容,如果未能解决你的问题,请参考以下文章

log4net到底有什么用?

c#中使用log4net工具记录日志

log4net 存储到oracle 调试 Could not load type [log4net.Appender.OracleAppender]

如何配置log4net以便log.IsDebugEnabled为true

log4net使用

log4net 配置