学习Logback

Logback 介绍

Logback 是 Log4j 的替代品,也是 Spring Boot 框架中的默认日志实现。性能优异、配置丰富且灵活,使其被广泛使用在 Java 项目中。

环境搭建

创建一个简单的 maven 项目。

引入依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.6.5</version>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.6.5</version>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.20</version>
<scope>compile</scope>
</dependency>

简单使用

在 resources 目录下创建 logback.xml 配置 logback,如果是 spring 项目,也可以使用 logback-spring.xml。

Logback 配置由三部分组成:Logger、Appender、Layout。三者的关系非常清晰:Logger 负责生成日志事件,Appender 决定日志往哪写,Layout 则控制日志长什么样。

最简单的使用方式就是将日志自定义格式化然后输出到控制台中,下面是 logback.xml 配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<!-- 定义变量 -->
<property name="LOG_HOME" value="logs/app"/>

<!-- 定义 Appender -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<!-- 输出到控制台 -->
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>

代码中增加日志打印:

1
2
3
4
5
6
7
8
9
10
11
12
package day.happy365.logbackdemo;

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

public class Main {
private static final Logger logger = LoggerFactory.getLogger(Main.class);

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

输出的日志样式 2026-10-12 19:48:37 [main] INFO day.happy365.logbackdemo.Main - Example log info

Layout 格式化

1
2
3
<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 换行符

指定特定包的日志输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8" ?>
<configuration debug="true">
<property name="LOG_HOME" value="C://Users/Roborock/Documents/projects/logback-demo/logs/aftersales"/>

<!-- 控制台 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<!-- 调整特定包的日志级别 -->
<logger name="com.example" level="INFO"/>

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

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package day.happy365.logbackdemo;

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

public class Main {
private static final Logger logger1 = LoggerFactory.getLogger("com.example");
private static final Logger logger2 = LoggerFactory.getLogger("com.example.xx");

public static void main(String[] args) {
logger1.debug("Example log debug of {}", "logger1");
logger1.info("Example log info of {}", "logger1");
logger2.debug("Example log debug of {}", "logger2");
logger2.info("Example log info of {}", "logger2");
}
}

输出:

1
2
2026-10-12 20:30:10 [main] INFO  com.example - Example log info of logger1
2026-10-12 20:30:10 [main] INFO com.example.xx - Example log info of logger2

日志样式的继承关系

Logger 会自动继承其父级日志配置,通过类的全限定名决定类的继承关系。例如 com.example 是 com.example.xx 的父级。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package day.happy365.logbackdemo;

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

public class Main {
private static final Logger logger1 = LoggerFactory.getLogger("com.example");
private static final Logger logger2 = LoggerFactory.getLogger("com.example.xx");

public static void main(String[] args) {
// 日志配置继承
logger1.debug("Example log debug of {}", "logger1");
logger1.info("Example log info of {}", "logger1");
logger2.debug("Example log debug of {}", "logger2");
logger2.info("Example log info of {}", "logger2");
}
}

输出:

1
2
3
4
2026-10-12 20:18:46 [main] DEBUG com.example - Example log debug of logger1
2026-10-12 20:18:46 [main] INFO com.example - Example log info of logger1
2026-10-12 20:18:46 [main] DEBUG com.example.xx - Example log debug of logger2
2026-10-12 20:18:46 [main] INFO com.example.xx - Example log info of logger2

参数化日志

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// ❌ 踩坑写法:无论是否输出,都会执行字符串拼接
log.debug("Current count is " + count);

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

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

```java
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);
}

输出:

1
2
3
4
5
6
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)
...

Appender 基本配置

1
2
3
4
5
6
7
8
9
10
11
<configuration>
<appender name="CONSOLE" 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="CONSOLE" />
</root>
</configuration>
  • appender 定义输出行为
  • encoder 内的 pattern 控制格式
  • root 设置根 Logger 级别并绑定 Appender

对 Spring 的支持:

test、prod 环境的输出行为控制:

1
2
3
4
5
6
7
8
<configuration>
...
<springProfile name="test,prod">
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
</configuration>

变量替换

通过 <property name="VAR_NAME" value="VAR_VAL"/> 定义变量,通过 ${VAR_NAME} 引用。

1
2
3
4
5
6
7
8
9
10
11
<configuration>
<!-- 变量定义 -->
<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>
</configuration>

Appender

ConsoleAppender

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

1
2
3
4
5
6
<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>

FileAppender

输出到指定文件:

1
2
3
4
5
6
7
<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>

RollingFileAppender

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

按天滚动 + 压缩归档

1
2
3
4
5
6
7
8
9
10
11
12
<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>

按月归档 + 自定义路径

1
2
3
4
5
6
7
8
<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 后缀自动启用压缩
  • maxHistory 和 totalSizeCap 防止磁盘被占满

自定义 Appender

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

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

配置中引用:

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

参考文献

Logback 使用指南

示例配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<configuration>
<property name="LOG_HOME" value="logs"></property>

<!-- 控制台 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<!-- 文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/app.%d{yyyy-MM-dd}.gz</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
</root>
</springProfile>

<springProfile name="prod">
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</springProfile>

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