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

文章目录

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

前言

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

功能简述

1. 自定义日志文件名

xml 复制代码
	<file>${log.path}/sys-info.log</file>

2. 归档规则 && 压缩

2.1. 归档配置

xml 复制代码
    <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

xml 复制代码
     <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>

源码伪代码

java 复制代码
    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. 日志格式 && 编码

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

现象

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

原因

归档伪代码

java 复制代码
	 // 无压缩
     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);
         }
     }
java 复制代码
    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 文件创建逻辑
相关推荐
Mr.Jessy8 分钟前
JavaScript高级:构造函数与原型
开发语言·前端·javascript·学习·ecmascript
ะัี潪ิื3 小时前
springboot加载本地application.yml和加载Consul中的application.yml配置反序列化LocalDate类型差异
spring boot·consul·java-consul
玄斎4 小时前
MySQL 单表操作通关指南:建库 / 建表 / 插入 / 增删改查
运维·服务器·数据库·学习·程序人生·mysql·oracle
m0_740043734 小时前
SpringBoot05-配置文件-热加载/日志框架slf4j/接口文档工具Swagger/Knife4j
java·spring boot·后端·log4j
招风的黑耳5 小时前
我用SpringBoot撸了一个智慧水务监控平台
java·spring boot·后端
大佐不会说日语~5 小时前
Spring AI Alibaba 的 ChatClient 工具注册与 Function Calling 实践
人工智能·spring boot·python·spring·封装·spring ai
Miss_Chenzr5 小时前
Springboot优卖电商系统s7zmj(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
程序员游老板5 小时前
基于SpringBoot3+vue3的爱心陪诊平台
java·spring boot·毕业设计·软件工程·课程设计·信息与通信
期待のcode5 小时前
Springboot核心构建插件
java·spring boot·后端
Miss_Chenzr6 小时前
Springboot旅游景区管理系统9fu3n(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·旅游