日志框架体系:Java 日志的前世今生
Java 日志框架经历过一段混乱的"战国时代"。
2015 年 Log4j 停止维护后,Log4j 2、SLF4J、Logback 各有拥趸,很多项目里甚至同时存在多个日志框架——光依赖冲突就够喝一壶的。
这段历史值得了解一下,因为现在的主流选择(SLF4J + Logback)正是这段竞争的结果。
日志框架发展历程
Log4j (1999) ──→ Log4j 2 (2012) ──→ SLF4J + Logback (现在)
│ │ │
└──── 已停止维护 ────┘ ┌──────┘
│ │
过渡期: 主流选择
SLF4J + Logback| 框架 | 说明 | 现状 |
|---|---|---|
| Log4j | Apache 的第一个日志框架 | 已停止维护(2015) |
| Log4j2 | Apache 重写,并发性能好 | 仍在维护 |
| SLF4J | 日志门面(抽象层),统一 API | 事实标准 |
| Logback | Log4j 作者重写,Spring Boot 默认 | 主流选择 |
SLF4J 门面模式
SLF4J 的设计思想很简单:面向接口编程,不面向实现。
应用代码
│
▼
SLF4J API(slf4j-api.jar)
│
├── jcl-over-slf4j.jar ← 把 Commons Logging 桥接到 SLF4J
├── log4j-over-slf4j.jar ← 把 Log4j 1.x 桥接到 SLF4J
│
▼
具体实现(Logback / Log4j2)这样做的好处:切换日志实现不需要改代码,只要换依赖。
java
// ❌ 直接用具体实现,切换要改代码
import org.apache.log4j.Logger;
public class BadExample {
static Logger logger = Logger.getLogger(BadExample.class); // 绑死了
}
// ✅ 用 SLF4J,不绑定具体实现
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GoodExample {
static Logger logger = LoggerFactory.getLogger(GoodExample.class);
// 实现可以是 Logback,也可以是 Log4j2,换依赖就行
}Logback 配置
xml
<!-- logback.xml -->
<configuration>
<!-- 定义变量 -->
<property name="LOG_HOME" value="/var/log/myapp"/>
<property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${PATTERN}</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}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${PATTERN}</pattern>
</encoder>
</appender>
<!-- 根日志 -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
<!-- 指定包的日志 -->
<logger name="com.example.service" level="DEBUG"/>
</configuration>基本使用
java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UserService {
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
public void register(User user) {
logger.info("用户注册: {}", user.getUsername());
try {
userRepository.save(user);
logger.info("用户 {} 注册成功", user.getUsername());
} catch (Exception e) {
logger.error("用户 {} 注册失败", user.getUsername(), e);
throw e;
}
}
}总结
- 用 SLF4J:不绑定具体实现,切换时不用改代码
- 推荐组合:SLF4J + Logback(Spring Boot 默认)
- 占位符
{}:延迟拼接,避免不必要的字符串操作 - 敏感信息禁记:密码、token 都要脱敏
SLF4J 是 Java 日志的"普通话",学会它,走遍天下项目都不怕。
