Skip to content

日志框架体系:Java 日志的前世今生

Java 日志框架经历过一段混乱的"战国时代"。

2015 年 Log4j 停止维护后,Log4j 2、SLF4J、Logback 各有拥趸,很多项目里甚至同时存在多个日志框架——光依赖冲突就够喝一壶的。

这段历史值得了解一下,因为现在的主流选择(SLF4J + Logback)正是这段竞争的结果。

日志框架发展历程

Log4j (1999) ──→ Log4j 2 (2012) ──→ SLF4J + Logback (现在)
    │                   │               │
    └──── 已停止维护 ────┘        ┌──────┘
              │                  │
         过渡期:           主流选择
     SLF4J + Logback
框架说明现状
Log4jApache 的第一个日志框架已停止维护(2015)
Log4j2Apache 重写,并发性能好仍在维护
SLF4J日志门面(抽象层),统一 API事实标准
LogbackLog4j 作者重写,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;
        }
    }
}

总结

  1. 用 SLF4J:不绑定具体实现,切换时不用改代码
  2. 推荐组合:SLF4J + Logback(Spring Boot 默认)
  3. 占位符 {}:延迟拼接,避免不必要的字符串操作
  4. 敏感信息禁记:密码、token 都要脱敏

SLF4J 是 Java 日志的"普通话",学会它,走遍天下项目都不怕。

基于 VitePress 构建