← 首页·文章列表

Java日志框架

在Java开发中,日志是排查问题、监控系统运行状态的核心工具。从JDK自带的日志系统到主流的Logback、Log4j2,再到日志门面SLF4J,各类框架各有优劣。本文将基于基础知识点,对Java常用日志框架进行全面扩展补充.

一、JDK日志(java.util.logging=JUL)

1.1 核心原理与定位

JUL是JDK 1.4版本内置的日志系统,无需额外引入依赖,属于“原生工具”。其设计遵循观察者模式,核心组件包括:Logger(日志记录器,负责产生日志)、Handler(处理器,负责日志输出目的地,如控制台、文件)、Formatter(格式化器,负责日志格式)、Level(日志级别,控制日志输出粒度)。

JUL的最大优势是“零依赖”,适合简单demo、原生Java程序场景;但缺点也十分明显——配置繁琐、功能薄弱、扩展性差,无法满足商业系统的复杂需求(如日志滚动、异步输出、多环境适配等),因此实际开发中很少直接使用。

1.2 核心配置

JUL的默认配置文件路径为 $JAVA_HOME/jre/lib/logging.properties,默认配置下日志级别为INFO,仅输出到控制台。若需自定义配置,可通过两种方式:

  1. 通过系统属性指定配置文件:启动时添加参数 -Djava.util.logging.config.file=自定义配置文件路径,覆盖默认配置。例如: java -Djava.util.logging.config.file=./my-logging.properties LogJDKTest

  2. 代码动态配置:无需配置文件,直接通过API设置Logger、Handler、Formatter等组件,适合临时调试场景。

1.3 日志级别与过滤规则

JUL定义了7个日志级别(从低到高):ALL < FINEST < FINER < FINE < CONFIG < INFO < WARNING < SEVERE < OFF,核心规则如下:

1.4 实操案例扩展

import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class LogJDKTest {
    // 获取Logger实例(建议使用类全限定名作为Logger名称,便于分级配置)
    private static Logger log = Logger.getLogger(LogJDKTest.class.getName());

    static {
        // 1. 移除默认Handler(避免重复输出,JUL默认会给根Logger添加ConsoleHandler)
        log.setUseParentHandlers(false);

        // 2. 创建控制台Handler
        ConsoleHandler consoleHandler = new ConsoleHandler();
        // 设置Handler级别(仅输出≥SEVERE的日志)
        consoleHandler.setLevel(Level.SEVERE);

        // 3. 自定义日志格式(默认格式较简陋,可通过SimpleFormatter优化)
        Formatter formatter = new SimpleFormatter() {
            @Override
            public String format(java.util.logging.LogRecord record) {
                // 格式:时间 线程名 级别 类名 - 日志消息
                return String.format("[%tF %tT] [%s] [%s] %s - %s%n",
                        record.getMillis(), record.getMillis(),
                        record.getThreadID(),
                        record.getLevel().getName(),
                        record.getSourceClassName(),
                        record.getMessage());
            }
        };
        consoleHandler.setFormatter(formatter);

        // 4. 给Logger添加Handler
        log.addHandler(consoleHandler);

        // 5. 设置Logger级别(全局过滤,需低于Handler级别才会生效)
        log.setLevel(Level.INFO);
    }

    public static void main(String[] args) {
        // 不同级别日志输出
        log.finest("FINEST 级别(最低,被过滤)");
        log.finer("FINER 级别(被过滤)");
        log.fine("FINE 级别(被过滤)");
        log.config("CONFIG 级别(被过滤)");
        log.info("INFO 级别(Logger级别满足,但Handler级别不满足,被过滤)");
        log.warning("WARNING 级别(Handler级别不满足,被过滤)");
        log.severe("SEVERE 级别(两者级别都满足,正常输出)");
    }
}

二、Log4j 1.x

2.1 核心优势与局限性

Log4j 1.x是Apache开源的日志框架,曾是Java开发的“标配”,相比JUL具有以下优势:

局限性:Log4j 1.x已于2015年停止维护,存在安全漏洞(如Log4j 1.2.17的反序列化漏洞),且不支持异步日志、动态配置重载等高级功能,目前已被Log4j 2.x、Logback替代。

2.2 核心组件详解

Log4j 1.x的核心组件遵循“日志分层模型”,分为三大类:

  1. Logger(日志记录器):负责产生日志,按名称分级(如 com.test.service 是 com.test 的子Logger),支持继承父Logger的配置。核心属性:

    1. name:Logger名称,通常使用类全限定名或包名。

    2. level:日志级别(TRACE < DEBUG < INFO < WARN < ERROR < FATAL),若未指定则继承父Logger级别。

    3. additivity:是否向上传递日志(默认true,子Logger的日志会传递给父Logger的Handler)。

  2. Appender(输出目的地):负责将日志输出到指定位置,常用实现类:

    1. ConsoleAppender:输出到控制台。

    2. FileAppender:输出到单个文件(不会滚动,文件会无限增大)。

    3. DailyRollingFileAppender:按时间滚动(如每天生成一个日志文件)。

    4. RollingFileAppender:按文件大小滚动(如文件超过10MB则生成新文件)。

    5. SMTPAppender:输出到邮件(用于异常告警)。

  3. Layout(日志格式化器):负责将日志事件转换为字符串,常用实现类:

    1. PatternLayout:自定义日志格式(最常用),支持占位符(如 %d 表示时间、%p 表示级别、%m 表示消息)。

    2. SimpleLayout:简单格式(仅包含级别和消息)。

    3. HTMLLayout:HTML格式(适合网页查看日志)。

2.3 配置文件

Log4j 1.x默认读取类路径下的 log4j.properties 文件,以下是完整配置案例:

### 1. 根Logger配置:格式为「级别, Appender1, Appender2...」
### 级别:DEBUG(输出所有≥DEBUG的日志),Appender:stdout(控制台)、D(日常日志)、E(错误日志)
log4j.rootLogger = DEBUG, stdout, D, E

### 2. 控制台Appender配置
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
# 输出目标:System.out(标准输出,黑色字体)、System.err(错误输出,红色字体)
log4j.appender.stdout.Target = System.out
# 日志格式:PatternLayout自定义格式
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
# 格式说明:
# [%-5p]:级别(左对齐,占5个字符,不足补空格)
# %d{yyyy-MM-dd HH:mm:ss,SSS}:时间(精确到毫秒)
# method:%l:调用日志的位置(类名.方法名(行号))
# %n:换行符
# %m:日志消息
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 3. 日常日志文件Appender(按天滚动)
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
# 日志文件路径(绝对路径或相对路径,相对路径基于项目根目录)
log4j.appender.D.File = E://logs/log.log
# 是否追加写入(true:追加,false:覆盖,默认true)
log4j.appender.D.Append = true
# 日志级别阈值(仅输出≥DEBUG的日志,与根Logger级别取交集)
log4j.appender.D.Threshold = DEBUG
# 日志格式
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
# 滚动规则:默认按天滚动,可通过DatePattern自定义(如按小时滚动:%d{yyyy-MM-dd HH})
log4j.appender.D.DatePattern = '.'yyyy-MM-dd

### 4. 错误日志文件Appender(按天滚动)
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = E://logs/error.log
log4j.appender.E.Append = true
# 仅输出≥ERROR的日志(过滤日常日志,只记录错误信息)
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 5. 自定义Logger配置(针对特定包/类)
# 对com.test.service包下的日志单独设置级别为INFO,仅输出到控制台
log4j.logger.com.test.service = INFO, stdout
# 关闭日志向上传递(避免重复输出到根Logger的Appender)
log4j.additivity.com.test.service = false

2.4 实操案例与注意事项

2.4.1 依赖引入

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

注意:若项目中同时引入了SLF4J,需避免依赖冲突,可排除Log4j 1.x的依赖,改用SLF4J桥接包

2.4.2 代码使用

import org.apache.log4j.Logger;

public class TestLog4j {
    // 获取Logger实例(建议使用当前类作为参数,自动关联类全限定名)
    private static Logger logger = Logger.getLogger(TestLog4j.class);

    public static void main(String[] args) {
        // 不同级别日志输出
        logger.debug("DEBUG 级别:调试信息(如参数值、方法执行开始)");
        logger.info("INFO 级别:普通业务信息(如接口调用成功)");
        logger.warn("WARN 级别:警告信息(如参数不合法、资源不足)");
        logger.error("ERROR 级别:错误信息(如接口调用失败、异常抛出)", new RuntimeException("模拟异常"));
        logger.fatal("FATAL 级别:致命错误(如系统崩溃、核心资源丢失)");
    }
}

2.4.3 常见问题

三、Log4j 2.x

3.1 核心升级点

Log4j 2.x是Apache对Log4j 1.x的重构版本,解决了1.x的诸多缺陷,同时吸收了Logback的优点,核心升级点如下:

3.2 依赖引入(Maven)

Log4j 2.x分为API和Core两个模块,需同时引入:

<dependencies>
<!-- Log4j 2.x API -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.23.1</version&gt;
    &lt;/dependency&gt;
    <!-- Log4j 2.x 核心实现 -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.23.1</version>
    </dependency>
    <!-- 可选:SLF4J桥接包(若项目使用SLF4J接口) -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.23.1</version>
    </dependency>
</dependencies>

注意:版本需保持一致,避免依赖冲突;若项目中存在Log4j 1.x依赖,需排除(如 <exclusion> 标签)。

3.3 核心配置详解)

Log4j 2.x默认读取类路径下的 log4j2.xml 文件,以下是生产级配置案例(含异步日志、滚动策略、多环境适配):

<?xml version="1.0" encoding="UTF-8"?&gt;
<!-- 配置文件:scan="true"(自动监测配置文件修改,默认每60秒),scanPeriod="30s"(监测间隔),debug="false"(关闭Log4j自身调试日志) -->
<Configuration status="WARN" scan="true" scanPeriod="30s"&gt;
    <!-- 1. 定义变量(便于统一维护路径、格式) -->
    <Properties>
        <Property name="LOG_HOME">./logs</Property>
        <Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
    &lt;/Properties&gt;

    <!-- 2. Appender配置(输出目的地) -->
    &lt;Appenders&gt;
        <!-- 2.1 控制台Appender -->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="${LOG_PATTERN}"/&gt;
            <!-- 过滤规则:仅输出≥INFO的日志 -->
            <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
        </Console>

        <!-- 2.2 滚动文件Appender(按时间+大小滚动) -->
        <RollingFile name="RollingFile" fileName="${LOG_HOME}/app.log" filePattern="${LOG_HOME}/app-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout pattern="${LOG_PATTERN}"/&gt;
            <!-- 滚动策略:按时间(每天)+ 大小(10MB)滚动,压缩归档文件 -->
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <SizeBasedTriggeringPolicy size="10MB"/&gt;
            &lt;/Policies&gt;
            <!-- 保留策略:最多保留30天的日志,超过自动删除 -->
            <DefaultRolloverStrategy max="30"/&gt;
        &lt;/RollingFile&gt;

        <!-- 2.3 错误日志Appender(单独输出错误信息) -->
        <RollingFile name="ErrorFile" fileName="${LOG_HOME}/error.log" filePattern="${LOG_HOME}/error-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
            <Policies>
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <SizeBasedTriggeringPolicy size="5MB"/>
            </Policies>
            <DefaultRolloverStrategy max="15"/>
        </RollingFile&gt;

        <!-- 2.4 异步Appender(默认开启,提升性能) -->
        <Async name="AsyncAppender">
            <AppenderRef ref="RollingFile"/>
            <AppenderRef ref="ErrorFile"/>
        &lt;/Async&gt;
    &lt;/Appenders&gt;

    <!-- 3. Logger配置 -->
    &lt;Loggers&gt;
        <!-- 3.1 自定义Logger(针对com.test包) -->
        <Logger name="com.test" level="DEBUG" additivity="false">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="AsyncAppender"/>
        </Logger>

       <!-- 3.2 第三方框架日志过滤(降低依赖包日志级别,避免刷屏) -->
        <Logger name="org.springframework" level="WARN"/>
        <Logger name="com.alibaba" level="WARN"/>

       <!-- 3.3 根Logger -->
        <Root level="INFO">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="AsyncAppender"/>
        </Root>
    </Loggers>
</Configuration>

3.4 代码使用与特性演示

3.4.1 基础使用(Log4j 2.x )

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class LoggerTest {
    // 获取Logger实例(推荐使用LogManager.getLogger(),支持自动关联类名)
    private static final Logger logger = LogManager.getLogger(LoggerTest.class);

    public static void main(String[] args) {
        // 1. 基础日志输出
        logger.trace("TRACE 级别:最细粒度调试信息");
        logger.debug("DEBUG 级别:调试信息");
        logger.info("INFO 级别:业务正常信息");
        logger.warn("WARN 级别:警告信息");
        logger.error("ERROR 级别:错误信息", new Exception("模拟业务异常"));
        logger.fatal("FATAL 级别:致命错误");

        // 2. 参数化日志(避免字符串拼接,提升性能)
        String username = "admin";
        int age = 25;
        // 格式:{} 作为占位符,自动替换参数
        logger.info("用户登录:用户名={}, 年龄={}", username, age);

        // 3. 自定义上下文信息(MDC,用于追踪链路)
        org.apache.logging.log4j.ThreadContext.put("traceId", "123456");
        logger.info("接口调用成功:/api/login");
        org.apache.logging.log4j.ThreadContext.clearMap(); // 清除上下文
    }
}

3.4.2 高级特性:参数化日志

Log4j 2.x支持参数化日志(logger.info("{}", param)),相比传统字符串拼接(logger.info("param: " + param))有两大优势:

3.5 常见问题与解决方案

四、Logback

4.1 核心优势(对比Log4j 2.x)

Logback是由Log4j创始人设计的开源日志框架,与SLF4J无缝集成,是目前主流的日志框架之一,核心优势如下:

4.2 核心模块与依赖引入

4.2.1 核心模块

4.2.2 依赖引入(Maven)

由于Logback-classic依赖SLF4J API,无需单独引入SLF4J:

    <!-- Logback 核心 -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.4.11</version&gt;
    &lt;/dependency&gt;
    <!-- Logback 实现SLF4J接口 -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version&gt;1.4.11&lt;/version&gt;
    &lt;/dependency&gt;
    <!-- 可选:SLF4J API(若项目中已引入,可省略) -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.9</version>
    </dependency>
</dependencies>

4.3 配置文件详解(XML格式)

Logback的配置文件加载优先级:logback-test.xml(测试环境)> logback.xml(生产环境)> 自动配置(无配置文件时)。以下是生产级配置案例:

&lt;?xml version="1.0" encoding="UTF-8"?&gt;
<!-- 配置文件:scan="true"(自动重载配置),scanPeriod="60 seconds"(重载间隔),debug="false"(关闭自身调试日志) -->
<configuration scan="true" scanPeriod="60 seconds" debug="false"&gt;
    <!-- 1. 定义变量 -->
    <property name="LOG_HOME" value="./logs"/>
    <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/&gt;

    <!-- 2. 控制台Appender -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${LOG_PATTERN}</pattern&gt;
            &lt;charset&gt;UTF-8&lt;/charset&gt; <!-- 解决中文乱码问题 -->
        &lt;/encoder&gt;
        <!-- 过滤规则:仅输出≥INFO的日志 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter&gt;
    &lt;/appender&gt;

    <!-- 3. 滚动文件Appender(按时间+大小滚动,压缩归档) -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        &lt;file&gt;${LOG_HOME}/app.log&lt;/file&gt; <!-- 当前日志文件 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/app-%d{yyyy-MM-dd}-%i.log.gz&lt;/fileNamePattern&gt; <!-- 归档文件格式 -->
            &lt;maxHistory&gt;30&lt;/maxHistory&gt; <!-- 保留30天日志 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>10MB&lt;/maxFileSize&gt; <!-- 单个文件最大10MB,超过则分割 -->
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder&gt;
    &lt;/appender&gt;

    <!-- 4. 错误日志Appender -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_HOME}/error.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/error-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
            <maxHistory>15</maxHistory>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>5MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
    </appender&gt;

    <!-- 5. 异步Appender(提升性能,不阻塞主线程) -->
    <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
        <discardingThreshold>0</discardingThreshold><!-- 不丢弃任何日志 -->
        <queueSize>256</queueSize&gt; <!-- 队列大小,默认256 -->
        <appender-ref ref="FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </appender>

    <!-- 6. Logger配置 -->
    &lt;loggers&gt;
        <!-- 6.1 自定义Logger(针对com.test包,级别为DEBUG) -->
        <logger name="com.test" level="DEBUG" additivity="false">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="ASYNC_FILE"/&gt;
        &lt;/logger&gt;

        <!-- 6.2 第三方框架日志过滤 -->
        <logger name="org.springframework" level="WARN"/>
        <logger name="com.alibaba" level="WARN"/>

        <!-- 6.3 根Logger -->
        <root level="INFO">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="ASYNC_FILE"/>
        </root>
    </loggers>
</configuration>

4.4 代码使用(SLF4J接口)

Logback推荐通过SLF4J接口使用(解耦日志实现,便于后续切换框架),代码如下:

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

public class LogbackTest {
    // 通过SLF4J获取Logger实例(与日志实现解耦)
    private static final Logger logger = LoggerFactory.getLogger(LogbackTest.class);

    public static void main(String[] args) {
        // 基础日志输出
        logger.info("INFO 级别:业务正常执行");
        logger.error("ERROR 级别:业务执行失败", new RuntimeException("模拟异常"));

        // 参数化日志(SLF4J原生支持)
        String orderId = "ORDER123456";
        logger.debug("订单创建成功:订单ID={}", orderId);

        // MDC上下文(追踪链路)
        org.slf4j.MDC.put("traceId", "654321");
        logger.info("接口调用:/api/order/create");
        org.slf4j.MDC.clear();
    }
}

4.5 关键特性:自动配置重载

Logback支持配置文件自动重载(无需重启应用),核心原理是通过后台线程定期扫描配置文件的修改时间,若发生变化则重新加载配置。配置方式:在<configuration>标签中设置scan="true"(默认true)和scanPeriod="60 seconds"(默认1分钟)。

注意:自动重载仅适用于本地文件系统中的配置文件,若配置文件放在Jar包中(如分布式应用),则无法触发重载。

五、日志门面:Commons-Logging(JCL)与SLF4J

日志门面(Logging Facade)是一套日志接口规范,不提供具体实现,核心作用是“解耦日志实现与业务代码”——业务代码面向门面接口编程,可在不修改代码的情况下切换日志实现框架(如从Log4j切换到Logback)。

5.1 Commons-Logging(JCL)

5.1.1 核心原理

JCL是Apache开源的日志门面,通过“动态绑定”机制在运行时查找日志实现,核心流程如下:

  1. 查找系统属性 org.apache.commons.logging.LogFactory,获取自定义LogFactory实现。

  2. 通过JDK服务发现机制(META-INF/services/org.apache.commons.logging.LogFactory)查找配置。

  3. 读取类路径下的 commons-logging.properties 文件,获取Log实现类。

  4. 默认绑定:若找到Log4j则使用Log4j,否则使用JUL,最后使用JCL内置的SimpleLog。

5.1.2 局限性

5.2 SLF4J(Simple Logging Facade for Java)

5.2.1 核心优势(对比JCL)

5.2.2 SLF4J桥接机制

SLF4J通过“桥接包”实现与不同日志框架的绑定,核心分为两种场景:

场景1:业务代码使用SLF4J接口,切换日志实现

只需引入对应日志实现的SLF4J绑定包,无需修改业务代码:

场景2:旧代码使用其他日志接口(如Log4j 1.x、JUL),统一迁移到SLF4J

使用“适配桥接包”将旧日志接口的输出重定向到SLF4J,再由SLF4J绑定具体实现:

注意:避免循环依赖(如同时引入 log4j-over-slf4j 和 slf4j-log4j12,会导致日志死循环)。

六、日志框架选型与最佳实践

6.1 框架选型建议

框架 适用场景 不适用场景
JUL 简单demo、原生Java程序、无额外依赖需求的场景 商业系统、复杂日志需求(如滚动、异步)
Log4j 1.x legacy项目(旧项目维护) 新项目、对安全和性能有要求的场景
Log4j 2.x 高并发、高吞吐量的系统(如电商、金融)、对性能和安全要求高的场景 简单项目(配置稍复杂,学习成本略高)
Logback 大多数Java项目(Web、微服务)、追求简洁配置和高性能的场景 对日志聚合、分布式追踪有极致需求的场景(可搭配ELK补充)

总结:新项目优先选择 SLF4J + Logback(配置简单、性能优异)或 SLF4J + Log4j 2.x(高并发场景),旧项目逐步迁移到SLF4J体系。