logback配置日志归档和删除

通用基本配置和说明

<!-- 定义一个名为 "RollingFile" 的 appender,用于滚动记录日志文件 -->
<appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
   <!-- 指定日志文件的路径和文件名 -->
    <file>${log.path}/foo.log</file>
    <!-- 配置日志文件的内容编码及格式 -->
    <encoder>
        <!-- 设置每条日志输出的具体格式 -->
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level  %class{36} %L - %msg%n</pattern>
        <!-- 设置日志文件的字符编码为 UTF-8 -->
        <charset>UTF-8</charset> 
    </encoder>
    <!-- 配置日志文件滚动的策略,支持基于时间和大小的滚动 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <!-- 滚动后的日志文件命名模式 -->
        <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/foo-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <!-- 单个日志文件的最大大小限制 -->
        <maxFileSize>20MB</maxFileSize>
        <!-- 保留历史日志文件的最大天数,执行删除的时候会从maxHistory天前开始 -->
        <maxHistory>7</maxHistory>
        <!-- 所有日志文件占用磁盘空间的最大容量 -->
        <totalSizeCap>10GB</totalSizeCap>
        <!-- 启动时清理不再需要的日志文件 -->
        <cleanHistoryOnStart>true</cleanHistoryOnStart>
    </rollingPolicy>
</appender>

注意最后一个配置项

建议是配置为true,这样每次启动就会检测是否需要清理过期的日志文件。
<cleanHistoryOnStart>true</cleanHistoryOnStart>

清理的触发时机和策略

  1. 配置了前面的启动时检查清理的属性,那么在启动时就会做一次。
  2. 每次写入log文件的时候也会检查一次。什么意思呢,就是我们在调用log.info、debug等输出内容的时候,具体的XXAppender实现会依据条件满足时,调用rollover();
    这个需要注意,下一次可用的清理时间时初始化时候就算好的,比如按天归档清理,那么这里就是下一天00:00:00,意味着什么呢,启动之后短时间内肯定不会执行清理,而是等运行到过了当天,对吧到凌晨0点之后才会触发。 那么如果你总是重启应用,然后又没配置cleanHistoryOnStart,你猜会不会给你清理,必然不会。

执行策略

依赖上面的rollingPolicy配置,其中清理会用到的属性是maxHistory:从多少天之前开始清理,比如配置为5,那就扫描是当前日期-5天的目录下的文件。totalSizeCap:大于这个总的容量,也会触发。

常见问题

  • 为什么我配置了清理,并没有清理掉文件、文件夹呢?
    首先需要明白如果没有配置每次启动都检测,那么就会依赖于执行周期,如果执行周期没有被触发就不会执行。
    另外如果文件夹、文件的名字被动过,不符合规则当然也扫描不到。
    还有一点,多个清理策略是针对rollingPolicy的,那么多个appender对应的每一个rollingPolicy中都得配置。《当然可以自定义通用策略来替换,配置一次,按需搞即可》
  • 为什么还有很久之前的文件夹放在哪里
    过了执行周期了,比如你之前并为正确配置清理,才刚配置成功。
    文件夹的删除规则是,必须是空文件夹,意味着里面的文件必须都先执行删除了才会删除文件夹(默认规则)。

代码简要说明

//程序启动加载配置后会初始化线程池
 public synchronized ScheduledExecutorService getScheduledExecutorService() {
        if (scheduledExecutorService == null) {
            scheduledExecutorService = ExecutorServiceUtil.newScheduledExecutorService();
        }
        return scheduledExecutorService;
    }
    
    //ExecutorServiceUtil.newScheduledExecutorService方法。默认线程池大小为8,名字为“logback-” 开头
    //其实最终只是创建了一个自定义线程(logback公用,不是转给清理用)名称的线程池,虽然使用的是Scheduled,使用的默认初始化是0延迟,也就是立即调用执行的)
    static public ScheduledExecutorService newScheduledExecutorService() {
        return new ScheduledThreadPoolExecutor(CoreConstants.SCHEDULED_EXECUTOR_POOL_SIZE, THREAD_FACTORY);
    }
	
	
    //如果没有cleanHistoryOnStart就执行清理,俺么就依赖于滚动策略。
    //RollingFileAppender中的方法,注意这里的rollover()就是清理入口,前提是满足triggeringPolicy.isTriggeringEvent条件。
    //这里的triggeringPolicy就是TimeBasedRollingPolicy(依据时间滚动),currentlyActiveFile就是配置的日志文件,比如d:\logs\foo.log,event是ILoggingEvent的实现,这里默认就是LoggingEvent
    //内部先按照配置的大小、日期去比较是否要触发清理。(文件大小超过maxFileSize、或者当前日期>=下一个检查日期【默认的次略日期是按天,比如每天00点】
    /**
    * 
    * This method differentiates RollingFileAppender from its super class.
    */
    @Override
    protected void subAppend(E event) {
        // The roll-over check must precede actual writing. This is the
        // only correct behavior for time driven triggers.

        // We need to synchronize on triggeringPolicy so that only one rollover
        // occurs at a time
        synchronized (triggeringPolicy) {
            if (triggeringPolicy.isTriggeringEvent(currentlyActiveFile, event)) {
                rollover();
            }
        }

        super.subAppend(event);
    }
posted @ 2024-09-29 12:42  冰雪女娲  阅读(129)  评论(0编辑  收藏  举报