Logback 1.6.1 发布:重点检查 TimeBasedRollingPolicy 的文件滚动配置

2026-07-28 24 预计阅读时间: 1 分钟
来源: oschina.net AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

Logback 1.6.1 已经发布。Logback 延续了 log4j 1.x 的发展脉络,并通过模块化架构覆盖普通 Java 应用、SLF4J 日志实现以及 HTTP 访问日志等场景。本次更新涉及 TimeBasedRollingPolicy 在设置 file 选项时的行为,因此,使用按时间滚动日志的服务值得优先检查配置并完成回归测试。

由于现有摘要没有给出该项变更的完整描述,本文不推断具体修复细节,而是围绕受影响配置给出一套可直接运行的验证方法。

三个模块分别解决什么问题

Logback 由三个主要模块组成:

  • logback-core:提供 Appender、Layout、滚动策略等基础能力,其他模块建立在它之上。
  • logback-classic:实现 SLF4J API,也是普通 Java、Spring 等应用最常使用的模块。
  • logback-access:面向 HTTP 访问日志,通常需要与支持它的 Servlet 容器或服务器集成。

业务项目一般不需要分别声明 coreclassic。直接依赖 logback-classic 时,构建工具会传递引入相应的核心模块。不要同时放入多个 SLF4J 日志实现,否则可能出现 provider 冲突或实际加载的实现与预期不符。

为什么要关注 file 与滚动策略的组合

使用 RollingFileAppender 时,以下两个配置承担不同职责:

  • <file> 指定当前正在写入的活动日志文件,例如 logs/app.log
  • <fileNamePattern> 指定归档文件的命名方式,例如 logs/archive/app.2025-01-01.log

不少生产配置希望活动文件名保持不变,便于日志采集器持续读取,同时每天把旧日志移动到归档目录。典型配置如下:

<file>logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>logs/archive/app.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>

这恰好属于“设置了 file 选项并使用 TimeBasedRollingPolicy”的组合。升级后应重点验证:

  1. 应用启动后是否继续写入固定的活动文件。
  2. 到达时间边界后,旧文件是否按 fileNamePattern 归档。
  3. 重启应用后是否错误覆盖、遗漏或重复归档文件。
  4. 日志采集器是否仍然跟踪正确的文件或 inode。
  5. 多实例是否误写同一路径;容器环境中挂载目录是否可写。

搭建一个可运行的滚动日志验证项目

下面的示例假设使用 JDK 11 或更高版本,并通过 Maven 运行。请根据项目实际 Java 基线以及 SLF4J 依赖关系确认兼容性。

创建目录:

mkdir -p logback-161-demo/src/main/java/com/example
mkdir -p logback-161-demo/src/main/resources
cd logback-161-demo

创建 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>logback-161-demo</artifactId>
    <version>1.0.0</version>

    <properties>
        <maven.compiler.release>11</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.6.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>3.5.0</version>
                <configuration>
                    <mainClass>com.example.App</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

创建 src/main/resources/logback.xml。为了便于测试,这里按分钟滚动;生产环境通常可以改为 %d{yyyy-MM-dd} 按天归档:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener"/>

    <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/app.log</file>
        <append>true</append>

        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/archive/app.%d{yyyy-MM-dd_HH-mm}.log</fileNamePattern>
            <maxHistory>5</maxHistory>
        </rollingPolicy>

        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="ROLLING"/>
    </root>
</configuration>

创建 src/main/java/com/example/App.java

package com.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class App {
    private static final Logger log = LoggerFactory.getLogger(App.class);

    public static void main(String[] args) throws InterruptedException {
        for (int i = 1; i <= 150; i++) {
            log.info("rolling-policy verification, sequence={}", i);
            Thread.sleep(1000);
        }
    }
}

运行并观察文件变化:

mvn clean compile exec:java

在另一个终端中执行:

find logs -type f -maxdepth 2 -print | sort
tail -f logs/app.log

程序跨越分钟边界后,预期可以继续看到 logs/app.log 作为活动文件,并在 logs/archive/ 下看到带时间戳的归档文件。这个例子用于验证滚动行为,不代表生产环境应该按分钟切割日志。

如果想观察 Logback 的内部决策,可保留示例中的 OnConsoleStatusListener。它会输出配置解析、Appender 启动及文件相关错误。完成排查后可以移除,以免增加控制台噪声。

升级时不要只看“应用能启动”

日志组件的回归测试需要覆盖时间边界,而不只是启动阶段。可以按下面的顺序推进:

  • 在测试环境保留旧版本生成的一组日志文件,然后升级到 1.6.1 并重启应用。
  • 临时把滚动周期缩短到分钟级,确认活动文件与归档文件的转换过程。
  • 检查应用用户对活动目录和归档目录是否都拥有写权限。
  • 确认磁盘清理策略符合预期,尤其是 maxHistory、外部清理任务与采集器之间的配合。
  • 检查依赖树,排除多个 Logback 版本或多个 SLF4J provider 同时存在的情况。

Maven 项目可以用下面的命令检查相关依赖:

mvn dependency:tree \
  -Dincludes=ch.qos.logback:*,org.slf4j:*

采用建议

如果项目没有使用文件滚动,也可以按常规补丁版本流程评估 1.6.1;如果配置中同时出现 RollingFileAppenderTimeBasedRollingPolicy<file>,则应把真实配置复制到预发布环境进行验证。

上线前至少确认四件事:活动日志持续写入、归档命名正确、重启不会破坏已有文件、日志采集链路没有中断。日志框架通常位于故障诊断链路的最底层,升级本身并不复杂,但一旦滚动或采集失效,问题往往要到真正需要日志时才会暴露。


相关推荐