1. 概述

Logback 是 Java 社区中最广泛使用的日志框架之一。它是其前身 Log4j 的替代品,不仅性能更优,还提供了更丰富的配置选项和更灵活的日志归档机制。

本文将带你深入理解 Logback 的核心架构,并掌握如何通过它提升应用的日志能力。✅

2. Logback 架构

Logback 的核心由三大组件构成:

  • Logger:日志的上下文,是应用中用于生成日志的入口
  • Appender:决定日志的最终输出位置(如控制台、文件等)
  • Layout:定义日志的输出格式

这三者的关系非常清晰:Logger 负责生成日志事件,Appender 决定日志往哪写,Layout 则控制日志长什么样。

3. 环境搭建

3.1. Maven 依赖

Logback 基于 SLF4J(Simple Logging Facade for Java)作为其原生接口。因此,使用前需引入以下依赖:

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.5.6</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>2.1.0-alpha1</version>
    <scope>test</scope>
</dependency>

🔍 最新版可参考 Maven Centralslf4j-api

3.2. 运行时依赖

若要在运行时使用 Logback,还需引入 logback-classic 模块:

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

⚠️ 注意:logback-classic.jar 是运行时必需的,否则会回退到默认的控制台输出。

4. 快速上手示例

我们从一个最简单的例子开始。

4.1 配置文件 logback.xml

在 classpath 下创建 logback.xml

<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

4.2 测试代码

public class Example {

    private static final Logger logger 
      = LoggerFactory.getLogger(Example.class);

    public static void main(String[] args) {
        logger.info("Example log from {}", Example.class.getSimpleName());
    }
}

运行后输出:

20:34:22.136 [main] INFO Example - Example log from Example

简单粗暴,几分钟就能跑起来,这正是 Logback 受欢迎的原因之一。

5. Logger 上下文

5.1. 创建 Logger

标准写法:

private static final Logger logger = LoggerFactory.getLogger(Example.class);

Logger 名称通常为类的全限定名,它构成了一套继承层级结构

  • ✅ 如果 A Logger 的名称是 B Logger 名称的前缀(以 . 分隔),则 A 是 B 的祖先
  • ✅ 最近的祖先即为父级
  • ✅ 所有 Logger 都继承自根 Logger(ROOT)

🔍 默认情况下,未显式设置级别的 Logger 会继承其最近祖先的级别。根 Logger 默认级别为 DEBUG

5.2. 层级与日志级别

演示代码:

ch.qos.logback.classic.Logger parentLogger = 
  (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.baeldung.logback");

parentLogger.setLevel(Level.INFO);

Logger childlogger = 
  (ch.qos.logback.classic.Logger)LoggerFactory.getLogger("com.baeldung.logback.tests");

parentLogger.warn("This message is logged because WARN > INFO.");
parentLogger.debug("This message is not logged because DEBUG < INFO.");
childlogger.info("INFO == INFO");
childlogger.debug("DEBUG < INFO");

输出:

20:31:29.586 [main] WARN com.baeldung.logback - This message is logged because WARN > INFO.
20:31:29.594 [main] INFO com.baeldung.logback.tests - INFO == INFO

结论:DEBUG 级别被过滤,说明层级继承生效。

5.3. 参数化日志(强烈推荐)

避免字符串拼接的性能损耗:

// ❌ 踩坑写法:无论是否输出,都会执行字符串拼接
log.debug("Current count is " + count);

// ✅ 正确姿势:仅当需要输出时才格式化
log.debug("Current count is {}", count);

支持多个参数,最后一个参数为异常时自动打印堆栈:

String message = "This is a String";
Integer zero = 0;

try {
    logger.debug("Logging message: {}", message);
    logger.debug("Going to divide {} by {}", 42, zero);
    int result = 42 / zero;
} catch (Exception e) {
    logger.error("Error dividing {} by {} ", 42, zero, e);
}

输出:

21:32:10.311 [main] DEBUG com.baeldung.logback.LogbackTests - Logging message: This is a String
21:32:10.316 [main] DEBUG com.baeldung.logback.LogbackTests - Going to divide 42 by 0
21:32:10.316 [main] ERROR com.baeldung.logback.LogbackTests - Error dividing 42 by 0
java.lang.ArithmeticException: / by zero
  at com.baeldung.logback.LogbackTests.givenParameters_ValuesLogged(LogbackTests.java:64)
...

6. 详细配置

6.1. 配置文件查找顺序

Logback 按以下顺序查找配置文件:

  1. logback-test.xml
  2. logback.xml
  3. 若未找到,则使用 ServiceLoader 查找自定义配置器
  4. 最终回退到默认的 ConsoleAppender

⚠️ 注意:官方已不再推荐使用 logback.groovy,建议统一使用 XML 配置。

6.2. 基本配置解析

回顾之前的 logback.xml

<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>
  • appender 定义输出行为
  • encoder 内的 pattern 控制格式
  • root 设置根 Logger 级别并绑定 Appender

6.3. 配置调试

开启 debug 模式,查看加载过程:

<configuration debug="true">
  ...
</configuration>

输出示例:

23:54:23,040 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback-test.xml] 
  at [file:/Users/egoebelbecker/ideaProjects/logback-guide/out/test/resources/logback-test.xml]
...

也可使用 StatusListener 实时监控状态:

<configuration>
    <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />  
    ...
</configuration>

✅ 适合排查类路径下多个配置文件冲突的问题。

6.4. 配置自动重载

开发时非常实用的功能:

<configuration scan="true" scanPeriod="15 seconds">
  ...
</configuration>
  • scan="true" 启用扫描
  • scanPeriod 可设为 milliseconds, seconds, minutes, hours

修改配置后无需重启应用,Logback 会自动重新加载。

6.5. 自定义 Logger 级别

通过配置文件设置特定包的级别:

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    <logger name="com.baeldung.logback" level="INFO" /> 
    <logger name="com.baeldung.logback.tests" level="WARN" /> 
    <root level="debug">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

测试代码:

Logger foobar = LoggerFactory.getLogger("com.baeldung.foobar");
Logger logger = LoggerFactory.getLogger("com.baeldung.logback");
Logger testslogger = LoggerFactory.getLogger("com.baeldung.logback.tests");

foobar.debug("This is logged from foobar");        // 输出(继承 root 的 DEBUG)
logger.debug("This is not logged from logger");    // 不输出(INFO 级别)
logger.info("This is logged from logger");         // 输出
testslogger.info("This is not logged from tests"); // 不输出(WARN 级别)
testslogger.warn("This is logged from tests");     // 输出

6.6. 变量替换

支持变量定义与外部注入:

<property name="LOG_DIR" value="/var/log/application" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>${LOG_DIR}/tests.log</file>
    <append>true</append>
    <encoder>
        <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
</appender>

变量来源优先级:

  1. 配置文件内 <property>
  2. JVM 系统属性(如 -DLOG_DIR=/custom/path
  3. 环境变量

✅ 推荐在部署时通过 -D 注入路径,避免硬编码。

7. Appender 详解

Appender 是日志落地的关键,Logback 提供了多种实现。

7.1. ConsoleAppender

输出到控制台(System.outSystem.err),使用缓冲 I/O,性能较好。

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <target>System.out</target>
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
</appender>

7.2. FileAppender

输出到指定文件:

<appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>tests.log</file>
    <append>true</append>
    <encoder>
        <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
</appender>

⚠️ 注意:additivity="false" 可关闭继承行为,避免日志重复输出。

7.3. RollingFileAppender

按时间或大小滚动日志文件,生产环境必备。

按天滚动 + 压缩归档

<property name="LOG_FILE" value="LogFile" />
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_FILE}.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.gz</fileNamePattern>
        <maxHistory>30</maxHistory>
        <totalSizeCap>3GB</totalSizeCap>
    </rollingPolicy>
    <encoder>
        <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
</appender> 

按月归档 + 自定义路径

<property name="LOG_DIR" value="/var/logs/application" />
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_DIR}/${LOG_FILE}.log</file> 
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>${LOG_DIR}/%d{yyyy/MM}/${LOG_FILE}.gz</fileNamePattern>
        <totalSizeCap>3GB</totalSizeCap>
    </rollingPolicy>
</appender>

关键点

  • %d{} 控制滚动周期(支持 yyyy-MM-dd, HH, mm 等)
  • .gz 后缀自动启用压缩
  • maxHistorytotalSizeCap 防止磁盘被占满

其他策略:

  • SizeAndTimeBasedRollingPolicy:按大小+时间双条件滚动
  • FixedWindowRollingPolicy:固定窗口滚动(较少用)

7.4. 自定义 Appender

可通过继承 AppenderBase<E> 实现自定义输出,如写入数据库、发送 MQ 消息等。

public class CustomAppender extends AppenderBase<ILoggingEvent> {
    @Override
    protected void append(ILoggingEvent event) {
        // 自定义逻辑
        System.out.println("Custom: " + event.getFormattedMessage());
    }
}

配置中引用:

<appender name="CUSTOM" class="com.example.CustomAppender" />

8. Layout 格式化

Layout 控制日志的最终输出样式,最常用的是 PatternLayout

8.1 PatternLayout 示例

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

常用转换词解析:

转换词 说明
%d{HH:mm:ss.SSS} 时间戳(精确到毫秒)
[%thread] 线程名
%-5level 日志级别,左对齐占 5 字符
%logger{36} Logger 名,最多 36 字符
%msg%n 日志内容 + 换行符

🔍 更多转换词参考官方文档:PatternLayout 文档

9. 总结

本文系统性地介绍了 Logback 的三大核心组件(Logger、Appender、Layout)及其配置方式。重点包括:

  • ✅ 参数化日志避免性能损耗
  • ✅ 层级化 Logger 与继承机制
  • RollingFileAppender 实现日志滚动与压缩
  • ✅ 配置自动重载与调试技巧
  • ✅ 变量替换实现环境适配

所有示例代码已托管至 GitHub:https://github.com/eugenp/tutorials/tree/master/logging-modules/logback


原始标题:A Guide To Logback | Baeldung