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-10-10
  • http中get请求与post请求区别及如何选择

    http中get请求与post请求区别及如何选择

    这篇文章主要介绍了http中get请求与post请求在应用中应该如何选择,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2021-09-09
  • Java实现大文件的分片上传与下载(springboot+vue3)

    Java实现大文件的分片上传与下载(springboot+vue3)

    这篇文章主要为大家详细介绍了java基于springboot+vue3如何大文件的分片上传与下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2023-06-06
  • 一文精通Java中的volatile关键字

    一文精通Java中的volatile关键字

    volatile是java中的关键词之一,这篇文章主要给大家介绍了关于Java中volatile关键字的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-05-05
  • Nacos(SpringBoot)配置加载及刷新方式

    Nacos(SpringBoot)配置加载及刷新方式

    文章主要介绍了NacosConfigAutoConfiguration的配置加载及刷新过程,包括NacosConfigBeanDefinitionRegistrar的注册、NacosPropertySource的处理、自动刷新机制以及NacosValueAnnotationBeanPostProcessor的实现
    2024-12-12
  • FluentMybatis实现mybatis动态sql拼装和fluent api语法

    FluentMybatis实现mybatis动态sql拼装和fluent api语法

    本文主要介绍了FluentMybatis实现mybatis动态sql拼装和fluent api语法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • springboot 加载本地jar到maven的实现方法

    springboot 加载本地jar到maven的实现方法

    如何在SpringBoot项目中加载本地jar到Maven本地仓库,使用Maven的install-file目标来实现,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2025-01-01
  • Scala常用List列表操作方法示例

    Scala常用List列表操作方法示例

    这篇文章主要介绍了Scala常用List列表操作方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-06-06
  • Ajax登录验证实现代码

    Ajax登录验证实现代码

    这篇文章主要为大家详细介绍了jQuery+ajax实现用户登录验证,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • Object.wait()与Object.notify()的用法详细解析

    Object.wait()与Object.notify()的用法详细解析

    以下是对java中Object.wait()与Object.notify()的用法进行了详细的分析介绍,需要的朋友可以过来参考下
    2013-09-09

最新评论