当前位置: 首页 > 知识库问答 >
问题:

日志文件追加器不会立即刷新

段宏毅
2023-03-14
jcl-over-slf4j-1.6.6.jar
logback-classic-1.0.6.jar
logback-core-1.0.6.jar
slf4j-api-1.6.6.jar
<configuration>
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/somepath/file.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <fileNamePattern>file.log.%i</fileNamePattern>
            <minIndex>1</minIndex>
            <maxIndex>3</maxIndex>
        </rollingPolicy>
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <maxFileSize>5MB</maxFileSize>
        </triggeringPolicy>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="debug">
        <appender-ref ref="FILE"/>
    </root>
</configuration>
    null

老实说,我已经通过实现自己的immediaterollingFileAppender解决了这个问题,它利用了FileDescriptor的即时同步功能。任何感兴趣的人都可以遵循这个。

所以这不是一个回滚问题。

共有1个答案

温智明
2023-03-14

我决定把我的解决方案带给大家。首先让我澄清一下,这不是一个回退问题,也不是一个JRE问题。这在javadoc中有描述,通常不应该是一个问题,除非您在文件同步方面遇到了一些老派的集成解决方案

因此,这是一个实现立即刷新的logback appender:

public class ImmediateFileAppender<E> extends RollingFileAppender<E> {

    @Override
    public void openFile(String file_name) throws IOException {
        synchronized (lock) {
            File file = new File(file_name);
            if (FileUtil.isParentDirectoryCreationRequired(file)) {
                boolean result = FileUtil.createMissingParentDirectories(file);
                if (!result) {
                    addError("Failed to create parent directories for [" + file.getAbsolutePath() + "]");
                }
            }

            ImmediateResilientFileOutputStream resilientFos = new ImmediateResilientFileOutputStream(file, append);
            resilientFos.setContext(context);
            setOutputStream(resilientFos);
        }
    }

    @Override
    protected void writeOut(E event) throws IOException {
        super.writeOut(event);
    }

}

这是相应的输出流实用程序类。由于最初用于扩展的ResilientOutputStreamBase的一些方法和字段都有打包的访问修饰符,所以我不得不扩展OutputStreamBase,并将ResilientOutputStreamBaseResilientFileOutputStreamStream的其余部分和未更改部分复制到这个新的方法和字段中。我只是显示更改后的代码:

public class ImmediateResilientFileOutputStream extends OutputStream {

    // merged code from ResilientOutputStreamBase and ResilientFileOutputStream

    protected FileOutputStream os;

    public FileOutputStream openNewOutputStream() throws IOException {
        return new FileOutputStream(file, true);
    }

    @Override
    public void flush() {
        if (os != null) {
            try {
                os.flush();
                os.getFD().sync(); // this's make sence
                postSuccessfulWrite();
            } catch (IOException e) {
                postIOFailure(e);
            }
        }
    }

}
<appender name="FOR_INTEGRATION" class="package.ImmediateFileAppender">
    <file>/somepath/for_integration.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
        <fileNamePattern>for_integration.log.%i</fileNamePattern>
        <minIndex>1</minIndex>
        <maxIndex>3</maxIndex>
    </rollingPolicy>
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
        <maxFileSize>5MB</maxFileSize>
    </triggeringPolicy>
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} - %msg%n</pattern>
        <immediateFlush>true</immediateFlush>
    </encoder>
</appender>
 类似资料:
  • 由于log4j的官方文档是一个断开的链接,而且入门指南对我没有帮助,所以我想知道如何使用文件而不是文件为同一个记录器使用两个具有不同日志级别的追加器。 例如,像这样:

  • 问题内容: 当我使用标准模块 logging 将日志写入文件时,是否将每个日志分别刷新到磁盘?例如,以下代码是否会将日志刷新10次? 如果是这样,它会变慢吗? 问题答案: 是的,它会在每次调用时刷新输出。您可以在的源代码中看到: 我真的不会介意日志记录的性能,至少在分析和发现它是瓶颈之前不会。无论如何,您始终可以创建一个在每次调用时都不会执行的子类(即使如果发生严重异常/解释器崩溃,也可能会丢失大

  • 我使用的是logback,日志位置将根据平台的不同而不同(请参见我的另一个相关问题:Java桌面应用程序中日志文件位置的最佳实践是什么?)。 如何告诉logback使用从平台确定的日志文件?我不能在logback.xml中硬编码日志文件,因为每个平台的日志文件都不同。 如何添加具有基于平台的位置的文件追加器。 如何让此文件追加器保留logback.xml中定义的设置。

  • 我有一个log4j配置XML,它有多个lple文件追加器。当我为我的应用程序构建一个新模块时,我希望再包含一个文件附加器,并仅使用该文件。有什么办法吗? 我尝试使用Logger.getLogger(MyAppender);但是在日志文件中,我应该得到类名...有了这个,我只得到日志文件中的appender名称。 我的appender配置是这样的。 " " 日志如下所示。。2013年10月31日10

  • 我遇到了一个奇怪的问题,我不明白: 当我删除我的文件appender时,它会阻止我登录到我的服务器,即使文件appender不应该负责将任何内容登录到服务器;这项任务应该只属于我的GELF appender。 下面的代码可以很好地登录到我的控制台和服务器 JAVA XML 但是,当我删除这个 和 它不再向我的服务器记录任何内容。 文件附件和记录器不应该只登录到文件而不是服务器吗?如果是这样,为什么