当前位置: 首页 > news >正文

聊聊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 freetry {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。

相关文章:

  • 从龙湖智创生活入选金钥匙联盟,透视物业服务力竞争风向
  • 专业课改革,难度陡然提高,专业课122总分390+南京理工大学818南理工818上岸经验分享
  • vue源码分析(七)—— createComponent
  • 蓝桥杯 Java 括号序列
  • 系统架构设计师-第19章-大数据架构设计理论与实践-软考学习笔记
  • Java AtomicInteger
  • postgresql的windows
  • 【EI会议征稿】第三届结构抗震与监测检测国际学术会议(SSRMD 2024)
  • Linux C语言开发-D15一维数组
  • 通过arthas vmtool 调用线上正在运行的service方法
  • rust学习-LinkedList
  • Anaconda下载安装以及环境变量的配置
  • 分布式消息队列:RabbitMQ(1)
  • kubernets挑战实验一(| pvc | pod | services | rolebinding | context)
  • 利用AI Chat 将电子书自动截屏并保存成pdf文件
  • 【Leetcode】101. 对称二叉树
  • 10个最佳ES6特性 ES7与ES8的特性
  • JAVA多线程机制解析-volatilesynchronized
  • k8s如何管理Pod
  • Linux CTF 逆向入门
  • Terraform入门 - 3. 变更基础设施
  • Tornado学习笔记(1)
  • Wamp集成环境 添加PHP的新版本
  • 大快搜索数据爬虫技术实例安装教学篇
  • 第2章 网络文档
  • 用Visual Studio开发以太坊智能合约
  • Nginx惊现漏洞 百万网站面临“拖库”风险
  • 带你开发类似Pokemon Go的AR游戏
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (1)(1.13) SiK无线电高级配置(五)
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (九十四)函数和二维数组
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (欧拉)openEuler系统添加网卡文件配置流程、(欧拉)openEuler系统手动配置ipv6地址流程、(欧拉)openEuler系统网络管理说明
  • (转)母版页和相对路径
  • (转)全文检索技术学习(三)——Lucene支持中文分词
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • (转载)(官方)UE4--图像编程----着色器开发
  • .NET : 在VS2008中计算代码度量值
  • .net core 依赖注入的基本用发
  • .NET Micro Framework初体验
  • @Bean注解详解
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • @DependsOn:解析 Spring 中的依赖关系之艺术
  • [ Algorithm ] N次方算法 N Square 动态规划解决
  • [ vulhub漏洞复现篇 ] Apache APISIX 默认密钥漏洞 CVE-2020-13945
  • [ 渗透测试面试篇 ] 渗透测试面试题大集合(详解)(十)RCE (远程代码/命令执行漏洞)相关面试题
  • [20180129]bash显示path环境变量.txt
  • [ARM]ldr 和 adr 伪指令的区别