Log4Net的RollingFileAppender在低日志量时未刷新IO缓冲区

19
我正在思考与HENRI COOK相同的问题。从简短的描述中可以看出,这已经被报告为Apache Jira上的错误
本质上我的问题是,只有在应用程序关闭时(甚至是事件发生数周后),才记录事件。当日志量非常低时就会发生这种情况。我在Windows Server 2008 R2上遇到了这个问题。这使我们无法捕获和响应生产错误。
现在,附加器不是缓冲型的。默认情况下,每次追加消息时它也会调用底层流的Flush()。

我的问题是为什么它没有刷新?除了编程方式刷新所有appender之外,还有什么解决办法吗?您是否考虑过使用pulsing appender作为可行的解决方法?

appender配置:

<appender name="RollingErrorFileAppender" type="log4net.Appender.RollingFileAppender">
  <param name="File" value="D:\LogFiles\zzzz\xxxxxx__ERROR" />
  <param name="AppendToFile" value="true" />
  <param name="DatePattern" value="_yyyyMMddHH&quot;.log&quot;" />
  <param name="RollingStyle" value="Date" />
  <param name="StaticLogFileName" value="false" />
  <filter type="log4net.Filter.LevelRangeFilter">
    <param name="LevelMin" value="ERROR" />
    <param name="LevelMax" value="FATAL" />
  </filter>
  <layout type="log4net.Layout.PatternLayout">
    <param name="ConversionPattern" value="%utcdate{yyyy-MM-dd HH:mm:ss.fff},[%thread],%level,%logger,%m%n"/>
  </layout>
</appender>

更新时间:2013-06-19

我无法通过任何代码重现此行为。无论我如何尝试,数据总是立即写入磁盘。然而,有一个重要的观察结果:如果对文件的第一次写入大于1KiB,则修改时间不会随后的写入而更新。只有在关闭文件时才会更新其关闭时间。另一方面,如果第一次写入是一个短的单行代码,则任何后续写入都将更新修改时间。这种行为在log4net和手动IO操作、32位WinXP和64位W2k8R2、.NET 2.0、3.5和.NET 4.0之间保持一致。虽然这并没有解决问题,但至少我现在可以理解奇怪的修改时间模式。

感谢,Rob


你能发布一下你正在使用的appender的配置吗? - Adam S
请澄清一下,如果在那段时间内至少发生了一个ERROR级别或更高级别的日志记录事件,您没有看到每小时滚动日志吗?我使用了您的appender进行测试,并看到日志正确地刷新和滚动。 - Adam S
@AdamS,通常问题会在以下情况下显现:1)应用程序启动时出现错误,然后应用程序保持静默 - 没有更多的日志事件来滚动日志。2)如果在滚动期之后有后续的日志事件,则先前的日志文件将被清除(我假设是因为IO流已经正确关闭)。在任何情况下,无法及时将日志事件写入文件。 - Robert Cutajar
1个回答

32

既然你只关心错误级别或更严重的日志事件,并且流量幸运地很少,我建议配置你的appender立即刷新。

<param name="ImmediateFlush" value="true" />

这样可以避免在每个日志事件上以编程方式刷新您的appender(从声音来看,这种方法也不起作用)。现在,如果您希望将appender打开到更多的日志级别,则立即刷新所有事件可能会有更大的性能问题。
编辑
我添加了配置文件和一个简单的主程序,用于测试。使用以下内容,我确实看到日志事件立即被刷新。关于您的评论,我还可以从xml中剥离ImmediateFlush行,并查看默认的true值是否适用于刷新。我在示例中保留了该行,以明确说明所需的行为。
基本主程序:
class Program
{
    static void Main(string[] args)
    {
        ILog log = LogManager.GetLogger(typeof(Program));
        XmlConfigurator.Configure(new FileInfo(@"C:\temp\logTest.config"));

        string msg;
        while ((msg = Console.ReadLine()) != "Done")
        {
            log.Error(msg);
        }

        LogManager.Shutdown();
    }
}

主程序引用的logTest.config:

<log4net>
    <appender name="RollingErrorFileAppender" type="log4net.Appender.RollingFileAppender">
        <param name="File" value="C:\temp\log" />
        <param name="AppendToFile" value="true" />
        <param name="DatePattern" value="_yyyyMMddHH&quot;.log&quot;" />
        <param name="RollingStyle" value="Date" />
        <param name="StaticLogFileName" value="false" />
        <param name="ImmediateFlush" value="true" />
        <filter type="log4net.Filter.LevelRangeFilter">
            <param name="LevelMin" value="ERROR" />
            <param name="LevelMax" value="FATAL" />
        </filter>
        <layout type="log4net.Layout.PatternLayout">
            <param name="ConversionPattern" value="%utcdate{yyyy-MM-dd HH:mm:ss.fff},[%thread],%level,%logger,%m%n"/>
        </layout>
    </appender>
    <root>
        <level value="INFO" />
        <appender-ref ref="RollingErrorFileAppender" />
    </root>
</log4net>

1
谢谢@AdamS,虽然我敢于不同意。如果您查看v1.2.10 TextWriterAppender中的private bool m_immediateFlush = true;override protected void Append(LoggingEvent loggingEvent)代码,您会同意我的观点,即ImmediateFlush默认为true,因此附加器实际上在每个Append()调用Flush(),正如我在问题中已经说过的那样。 - Robert Cutajar
1
我修改了我的回答,并加入了我使用的测试程序。通过这个程序,我能立刻看到事件的刷新。你没有看到同样的行为吗? - Adam S
谢谢AdamS,这是个好主意。我明天会尝试的。 - Robert Cutajar
AdamS,我更新了Q-UPDATE 2013-06-19。非常感谢你迄今为止所付出的努力。我想一个可以接受的答案确实可能会听起来像“如果你无法重现它,那么它就不是一个bug” :D 我开始怀疑在警报收集器中可能存在问题。 - Robert Cutajar
7
已解决!问题出在Windows Server 2008和我们的日志解析工具上。W2k8自带延迟修改时间更新的“功能”:http://blogs.technet.com/b/asiasupp/archive/2010/12/14/file-date-modified-property-are-not-updating-while-modifying-a-file-without-closing-it.aspx,而我们的工具会在3天后删除日志文件检查点。这两个因素加在一起,导致了记录延迟的虚假感和混乱。重现的行为是,除非关闭文件写句柄,否则不会更新修改时间,但如果第一次写入很小,则之后的每次写入都会更新。这是一个奇怪的功能。 - Robert Cutajar
我来总结一下问题:当你记录某些内容到日志中时,你期望该行内容立即出现并导致文件增长,但实际上并没有发生,你认为刷新没有起作用。你一遍又一遍地在资源管理器中按 F5,但文件大小仍然保持不变。解决办法?通过其他应用程序访问文件句柄。对我来说,只需要右键单击文件就可以了。 - Pavel Shkleinik

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