logback的FileAppender文件追加模式和冲突检测解读

 更新时间:2023年10月30日 10:02:11   作者:codecraft  
这篇文章主要为大家介绍了logback的FileAppender文件追加模式和冲突检测解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

本文主要研究一下logback的FileAppender

FileAppender

ch/qos/logback/core/FileAppender.java

public class FileAppender<E> extends OutputStreamAppender<E> {
    public static final long DEFAULT_BUFFER_SIZE = 8192;
    static protected String COLLISION_WITH_EARLIER_APPENDER_URL = CODES_URL + "#earlier_fa_collision";
    /**
     * Append to or truncate the file? The default value for this variable is
     * <code>true</code>, meaning that by default a <code>FileAppender</code> will
     * append to an existing file and not truncate it.
     */
    protected boolean append = true;
    /**
     * The name of the active log file.
     */
    protected String fileName = null;
    private boolean prudent = false;
    private FileSize bufferSize = new FileSize(DEFAULT_BUFFER_SIZE);
    //......
}
FileAppender继承了OutputStreamAppender,它定义了append、prudent、bufferSize属性

start

public void start() {
        int errors = 0;
        if (getFile() != null) {
            addInfo("File property is set to [" + fileName + "]");
            if (prudent) {
                if (!isAppend()) {
                    setAppend(true);
                    addWarn("Setting \"Append\" property to true on account of \"Prudent\" mode");
                }
            }
            if (checkForFileCollisionInPreviousFileAppenders()) {
                addError("Collisions detected with FileAppender/RollingAppender instances defined earlier. Aborting.");
                addError(MORE_INFO_PREFIX + COLLISION_WITH_EARLIER_APPENDER_URL);
                errors++;
            } else {
                // file should be opened only if collision free
                try {
                    openFile(getFile());
                } catch (java.io.IOException e) {
                    errors++;
                    addError("openFile(" + fileName + "," + append + ") call failed.", e);
                }
            }
        } else {
            errors++;
            addError("\"File\" property not set for appender named [" + name + "].");
        }
        if (errors == 0) {
            super.start();
        }
    }
start方法要求fileName必须有值,在prudent模式下会强制开启append;另外start的时候会执行checkForFileCollisionInPreviousFileAppenders判断是否有冲突,没有冲突则执行openFile方法

checkForFileCollisionInPreviousFileAppenders

protected boolean checkForFileCollisionInPreviousFileAppenders() {
        boolean collisionsDetected = false;
        if (fileName == null) {
            return false;
        }
        @SuppressWarnings("unchecked")
        Map<String, String> map = (Map<String, String>) context.getObject(CoreConstants.FA_FILENAME_COLLISION_MAP);
        if (map == null) {
            return collisionsDetected;
        }
        for (Entry<String, String> entry : map.entrySet()) {
            if (fileName.equals(entry.getValue())) {
                addErrorForCollision("File", entry.getValue(), entry.getKey());
                collisionsDetected = true;
            }
        }
        if (name != null) {
            map.put(getName(), fileName);
        }
        return collisionsDetected;
    }
checkForFileCollisionInPreviousFileAppenders方法从上下文读取FA_FILENAME_COLLISION_MAP,判断有没有文件名重复的,有则返回true

openFile

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

            ResilientFileOutputStream resilientFos = new ResilientFileOutputStream(file, append, bufferSize.getSize());
            resilientFos.setContext(context);
            setOutputStream(resilientFos);
        } finally {
            lock.unlock();
        }
    }
openFile方法加锁创建file,然后通过createMissingParentDirectories来创建不存在的父目录,最后创建根据file、append参数、bufferSize来创建ResilientFileOutputStream

stop

public void stop() {
        super.stop();

        Map<String, String> map = ContextUtil.getFilenameCollisionMap(context);
        if (map == null || getName() == null)
            return;

        map.remove(getName());
    }
stop方法会获取FA_FILENAME_COLLISION_MAP,移除当前文件名

writeOut

protected void writeOut(E event) throws IOException {
        if (prudent) {
            safeWrite(event);
        } else {
            super.writeOut(event);
        }
    }
FileAppender覆盖了OutputStreamAppender的writeOut方法,在prudent为true时执行safeWrite

safeWrite

private void safeWrite(E event) throws IOException {
        ResilientFileOutputStream resilientFOS = (ResilientFileOutputStream) getOutputStream();
        FileChannel fileChannel = resilientFOS.getChannel();
        if (fileChannel == null) {
            return;
        }
        // Clear any current interrupt (see LOGBACK-875)
        boolean interrupted = Thread.interrupted();
        FileLock fileLock = null;
        try {
            fileLock = fileChannel.lock();
            long position = fileChannel.position();
            long size = fileChannel.size();
            if (size != position) {
                fileChannel.position(size);
            }
            super.writeOut(event);
        } catch (IOException e) {
            // Mainly to catch FileLockInterruptionExceptions (see LOGBACK-875)
            resilientFOS.postIOFailure(e);
        } finally {
            if (fileLock != null && fileLock.isValid()) {
                fileLock.release();
            }
            // Re-interrupt if we started in an interrupted state (see LOGBACK-875)
            if (interrupted) {
                Thread.currentThread().interrupt();
            }
        }
    }
safeWrite会通过fileChannel.lock()进行加锁,然后执行fileChannel.position(size),最后通过父类writeOut进行写入;对于IOException会执行resilientFOS.postIOFailure(e)

小结

logback的FileAppender继承了OutputStreamAppender,它定义了append、prudent、bufferSize属性,它使用的是ResilientFileOutputStream,其writeOut方法主要是新增了对prudent模式的支持,在prudent为true时采用的是safeWrite。

以上就是logback的FileAppender文件追加模式和冲突检测解读的详细内容,更多关于logback FileAppender冲突检测的资料请关注脚本之家其它相关文章!

相关文章

  • Java编程实现时间和时间戳相互转换实例

    Java编程实现时间和时间戳相互转换实例

    这篇文章主要介绍了什么是时间戳,以及Java编程实现时间和时间戳相互转换实例,具有一定的参考价值,需要的朋友可以了解下。
    2017-09-09
  • Win10系统下配置java环境变量的全过程

    Win10系统下配置java环境变量的全过程

    这篇文章主要给大家介绍了关于Win10系统下配置java环境变量的相关资料,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • spring 项目实现限流方法示例

    spring 项目实现限流方法示例

    这篇文章主要为大家介绍了spring项目实现限流的方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • SpringBoot读取resource文件代码实例

    SpringBoot读取resource文件代码实例

    这篇文章主要介绍了SpringBoot读取resource文件代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • IDEA错误:找不到或无法加载主类的完美解决方法

    IDEA错误:找不到或无法加载主类的完美解决方法

    使用IDEA开始就一直在搭建java环境,许久没有使用过java,刚开始有些生疏,先建了一个最简单的类可是运行的时候出现错误:找不到或无法加载主类,下面这篇文章主要给大家介绍了关于IDEA错误:找不到或无法加载主类的完美解决方法,需要的朋友可以参考下
    2022-07-07
  • 详谈springboot过滤器和拦截器的实现及区别

    详谈springboot过滤器和拦截器的实现及区别

    今天小编就为大家分享一篇详谈springboot过滤器和拦截器的实现及区别,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-08-08
  • Java爬虫Jsoup+httpclient获取动态生成的数据

    Java爬虫Jsoup+httpclient获取动态生成的数据

    这篇文章主要介绍了Java爬虫Jsoup+httpclient获取动态生成的数据的相关资料,需要的朋友可以参考下
    2017-05-05
  • Springboot使用POI实现导出Excel文件示例

    Springboot使用POI实现导出Excel文件示例

    本篇文章主要介绍了Springboot使用POI实现导出Excel文件示例,非常具有实用价值,需要的朋友可以参考下。
    2017-02-02
  • Spring Cloud Feign接口返回流的实现

    Spring Cloud Feign接口返回流的实现

    这篇文章主要介绍了Spring Cloud Feign接口返回流的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • 多模块项目使用枚举配置spring-cache缓存方案详解

    多模块项目使用枚举配置spring-cache缓存方案详解

    这篇文章主要为大家介绍了多模块项目使用枚举配置spring-cache缓存的方案详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05

最新评论