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

Springboot 学习 之 logback-spring.xml 日志压缩 .tmp 临时文件问题

文章目录

  • 前言
  • 功能简述
    • 1. 自定义日志文件名
    • 2. 归档规则 && 压缩
      • 2.1. 归档配置
      • 2.2. 归档压缩
      • 2.3. 日志格式 && 编码
  • 现象
  • 原因
  • 解决办法

前言

Springboot 应用中,默认使用 logback-spring.xml 配置日志相关

功能简述

1. 自定义日志文件名

	<file>${log.path}/sys-info.log</file>

2. 归档规则 && 压缩

2.1. 归档配置

    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <!-- 日志文件名格式 -->
        <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
        <!-- 单个文件最大大小 -->
        <maxFileSize>50MB</maxFileSize>
        <!-- 日志最大的历史 60天 -->
        <maxHistory>60</maxHistory>
    </rollingPolicy>

2.2. 归档压缩

通过 <fileNamePattern> 文件后缀判断是否压缩,支持 GZZIP

     <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
         <!-- 日志文件名格式 -->
         <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
         <!-- 单个文件最大大小 -->
         <maxFileSize>50MB</maxFileSize>
         <!-- 日志最大的历史 60天 -->
         <maxHistory>60</maxHistory>
     </rollingPolicy>

源码伪代码

    switch (compressionMode) {
	    case GZ:
	        if (fileNamePatternStr.endsWith(".gz"))
	            return fileNamePatternStr.substring(0, len - 3);
	        else
	            return fileNamePatternStr;
	    case ZIP:
	        if (fileNamePatternStr.endsWith(".zip"))
	            return fileNamePatternStr.substring(0, len - 4);
	        else
	            return fileNamePatternStr;
	    case NONE:
	        return fileNamePatternStr;
    }

2.3. 日志格式 && 编码

     <encoder>
     	 <!-- 编码 -->
         <charset>UTF-8</charset>
     	 <!-- 日志格式 -->
         <pattern>${log.pattern}</pattern>
     </encoder>

现象

多个进程或者实例 的日志同时打印在 同一个文件 中,且日志文件归档使用 压缩,日志目录下出现了大量的 .tmp 临时文件,占用内存

原因

归档伪代码

	 // 无压缩
     if (compressionMode == CompressionMode.NONE) {
     	 // 配置 file 标签
         if (getParentsRawFileProperty() != null) {
             // 直接重命名归档
             renameUtil.rename(getParentsRawFileProperty(), elapsedPeriodsFileName);
         } 
     } else { // 压缩
     	 // 未配置 file 标签
         if (getParentsRawFileProperty() == null) {
         	 // 直接压缩归档
             compressionFuture = compressor.asyncCompress(elapsedPeriodsFileName, elapsedPeriodsFileName, elapsedPeriodStem);
         } else {
             // 先重命名为 .tmp 文件,然后再压缩归档;
             compressionFuture = renameRawAndAsyncCompress(elapsedPeriodsFileName, elapsedPeriodStem);
         }
     }
    private void gzCompress(String nameOfFile2gz, String nameOfgzedFile) {
    	// 源文件(可能是 .log 也可能是 .log.tmp 文件)
        File file2gz = new File(nameOfFile2gz);
        if (!file2gz.exists()) {
            return;
        }

		// 目标压缩文件
        if (!nameOfgzedFile.endsWith(".gz")) {
            nameOfgzedFile = nameOfgzedFile + ".gz";
        }
        File gzedFile = new File(nameOfgzedFile);
        // 如果目标文件已存在,则直接返回;不同版本写法略有不同,但大同小异;
        // 此处多进程或实例同时操作时,可能出现后边执行归档操作的进程直接 return,未执行删除逻辑
        if (gzedFile.exists()) {
            return;
        }

        ......    

        BufferedInputStream bis = null;
        GZIPOutputStream gzos = null;
        try {
            bis = new BufferedInputStream(new FileInputStream(nameOfFile2gz));
            gzos = new GZIPOutputStream(new FileOutputStream(nameOfgzedFile));
			......
			// 如果源文件存在,则删除
            if (!file2gz.delete()) {
                addStatus(new WarnStatus("Could not delete [" + nameOfFile2gz + "].", this));
            }
        } catch (Exception e) {
        	......    
        } finally {
        	......    
        }
    }

解决办法

  • 不压缩:直接归档原始日志文件,不存在此问题
  • 压缩:不使用 <file> 标签,可以跳过 .tmp 文件创建逻辑

http://www.kler.cn/a/445175.html

相关文章:

  • 基于java web在线商城购物系统源码+论文
  • 部署开源大模型的硬件配置全面指南
  • 数据分析实战—鸢尾花数据分类
  • 清远榉之乡托养机构为你深度分析:特殊碳水化合物饮食对自闭症的作用
  • fastAPI接口的请求与响应——基础
  • 如何去设计一个消息队列
  • 学习反射(反射的使用,反射的应用场景)
  • 51c自动驾驶~合集42
  • 使用 acme.sh 申请域名 SSL/TLS 证书完整指南
  • 基础库正则表达式
  • 【模块一】kubernetes容器编排进阶实战之基于velero及minio实现etcd数据备份与恢复
  • 【人工智能数学基础】——深入详解贝叶斯理论:掌握贝叶斯定理及其在分类和预测中的应用
  • 【Flutter_Web】Flutter编译Web第二篇(webview篇):flutter_inappwebview如何改造方法,变成web之后数据如何交互
  • 短视频账号矩阵系统源代码-代码分享
  • 基于注意力机制的faster-rcnn算法的目标检测(源码+pytorch框架)
  • Win10将WindowsTerminal设置默认终端并添加到右键(无法使用微软商店)
  • Javascript中如何实现函数缓存?函数缓存有哪些应用场景?
  • Windows11 离线更新 WSL
  • 电脑问题4[非华为电脑安装华为电脑管家华为荣耀手机多屏协助]
  • 分布式专题(6)之MongoDB复制(副本)集实战及其原理分析
  • MySQL复制问题和解决
  • 企业出海怎样通过SD-WAN解决网络难题
  • 一文学习什么是马尔科夫决策过程(Markov Decision Process, MDP)、以及它的变体POMDP、Dec_POMDP等
  • 数据管理的演进之路:从自建系统迈向云原生时代
  • 阿里云百炼大模型生成贪吃蛇小游戏
  • 如何正确地安装和配置帝国CMS系统?