Log4J、Log4J2和LogBack的历史故事 📅 2026/7/1 1:36:54 使用过Log4J和LogBack的同学肯定能发现这两个框架的设计理念极为相似使用方法也如出一辙。其实这个两个框架的作者都是一个人Ceki Gülcü俄罗斯程序员。Log4J 最初是基于Java开发的日志框架发展一段时间后作者Ceki Gülcü将Log4j捐献给了Apache软件基金会使之成为了Apache日志服务的一个子项目。 又由于Log4J出色的表现后续又被孵化出了支持C, C, C#, Perl, Python, Ruby等语言的子框架。然而伟大的程序员好像都比较有个性。Ceki Gülcü由于不满Apache对Log4J的管理决定不再参加Log4J的开发维护。“出走”后的Ceki Gülcü另起炉灶开发出了LogBack这个框架SLF4J是和LogBack一起开发出来的。LogBack改进了很多Log4J的缺点在性能上有了很大的提升同时使用方式几乎和Log4J一样许多用户开始慢慢开始使用LogBack。由于受到LogBack的冲击Log4J开始式微。终于2015年9月Apache软件基金业宣布Log4j不在维护建议所有相关项目升级到Log4j2。Log4J2是Apache开发的一个新的日志框架改进了很多Log4J的缺点同时也借鉴了LogBack号称在性能上也是完胜LogBack。性能这块后面我会仔细分析。那slf4j和这些有什么关系SLF4J的全称是Simple Logging Facade for Javaslf4j是门面模式的典型应用回答这个问题之前我们先看看如果需要用上面几个日志框架来打印日志一般怎么做具体代码如下java// 使用log4j需要log4j.jar import org.apache.log4j.Logger; Logger logger_log4j Logger.getLogger(Test.class); logger_log4j.info(Hello World!); // 使用log4j2需要log4j-api.jar、log4j-core.jar import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; Logger logger_log4j2 LogManager.getLogger(Test.class); logger_log4j2.info(Hello World!); // logback需要logback-classic.jar、logback-core.jar import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; Logger logger_logback new LoggerContext().getLogger(Test.class); logger_logback.info(Hello World!);从上面不难看出使用不同的日志框架就要引入不同的jar包使用不同的代码获取Logger。如果项目升级需要更换不同的框架那么就需要修改所有的地方来获取新的Logger这将会产生巨大的工作量。基于此我们需要一种接口来将不同的日志框架的使用统一起来这也是为什么要使用slf4j的原因。SLF4J即简单日志门面Simple Logging Facade for Java不是具体的日志解决方案它只服务于各种各样的日志系统。按照官方的说法SLF4J是一个用于日志系统的简单Facade允许最终用户在部署其应用时使用其所希望的日志系统。注意类似的日志门面还有Jakarta Common loggingJCL主要区别在于SLF4J是一个比较新的日志框架它更加灵活性能更好支持更多的日志实现而且JCL基于classLoader在运行时动态加载日志框架可能会产生很多意想不到的安全问题通过上面的介绍我们可以知道JCL和SLF4J都是日志门面Facade而Log4J、Log4J2和LogBack都是子系统角色SunSystem也就是具体的日志实现框架。他们的关系如下JUL是JDK本身提供的一种实现。SLF4J 的核心价值在于它提供了解耦设计应用程序代码只依赖 slf4j-api而具体日志实现如 Logback、Log4j2可以在部署时动态绑定。这种架构使得项目升级或更换日志框架变得非常简单无需修改业务代码中的日志记录语句。slf4j怎么和日志框架结合使用使用slf4j后当我们在打印日志时就可以使用下面的方式javaimport org.slf4j.Logger; import org.slf4j.LoggerFactory; Logger logger LoggerFactory.getLogger(Test.class); logger.info(Hello World!)这又引入了另外一个问题slf4j如何决定使用哪个框架日志呢并且引入哪些jar包呢官方为我们准备了组合依赖slf4j logback slf4j-api.jar logback-classic.jar logback-core.jarslf4j log4j slf4j-api.jar slf4j-log412.jar log4j.jarslf4j jul slf4j-api.jar slf4j-jdk14.jar也可以只用slf4j无日志实现slf4j-api.jar slf4j-nop.jarSLF4J 的基本使用在代码中使用 SLF4J 非常简单首先需要通过 Maven 添加依赖xml!-- Maven 依赖配置 -- dependencies !-- SLF4J API -- dependency groupIdorg.slf4j/groupId artifactIdslf4j-api/artifactId version2.0.9/version /dependency !-- Logback Classic 实现 -- dependency groupIdch.qos.logback/groupId artifactIdlogback-classic/artifactId version1.4.11/version /dependency /dependencies在代码中获取 Logger 并记录日志javaimport org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ExampleService { // 获取Logger实例 private static final Logger logger LoggerFactory.getLogger(ExampleService.class); public void processUser(String userId) { logger.debug(Processing user: {}, userId); // 使用占位符避免字符串拼接 logger.info(User processing started); try { // 业务逻辑 logger.info(User {} processed successfully, userId); } catch (Exception e) { logger.error(Failed to process user: userId, e); // 记录异常信息 } } }SLF4J 的 参数化日志消息使用{}占位符是其一个重要特性它不仅有更好的可读性还能提升性能——当日志级别高于当前配置时如配置为 INFO 级别时调用 debug 语句不会执行字符串拼接操作。Logback 架构与核心组件Logback 是 SLF4J 的原生实现框架由三个相互协作的模块组成每个模块都有独特的功能定位Logback 的模块化设计模块说明logback-core核心模块提供基础日志服务其他两个模块都依赖它logback-classic实现 SLF4J API完全兼容 SLF4J 接口同时兼容 Log4jlogback-access与 Servlet 容器集成用于 HTTP 访问日志记录Logback 相比 Log4j 有显著性能提升特别是在异步日志记录方面减少了线程阻塞和上下文切换开销。它还支持自动重载配置可以在不重启应用的情况下修改日志配置。Logback 核心概念Logback 架构基于三个核心概念Logger、Appender 和 Layout/Encoder。Logger日志记录器采用层次化命名如com.example.service.UserService具有继承性子 Logger 继承父 Logger 的 Appender 和 Level通过LoggerFactory.getLogger()获取实例Appender输出目的地Appender 负责将日志事件发送到不同目标Logback 支持多种 AppenderAppender 类型说明ConsoleAppender输出到控制台FileAppender输出到文件RollingFileAppender滚动文件按大小/时间SocketAppender发送到远程服务器SMTPAppender邮件告警KafkaAppender发送到 Kafka需扩展Layout/Encoder格式化器定义日志输出格式常用占位符包括%d{yyyy-MM-dd HH:mm:ss.SSS}时间戳%level日志级别%thread线程名%logger{36}Logger 名缩写%msg日志消息%n换行符Logback 配置详解与案例Logback 支持 XML 和 Groovy 两种配置格式其中 XML 是最常用的方式。下面通过实际案例详细讲解 Logback 的配置。基础配置结构Logback 配置文件通常命名为logback.xml或logback-spring.xmlSpring 环境放置在src/main/resources/目录下。xml?xml version1.0 encodingUTF-8? configuration scantrue scanPeriod30 seconds !-- 定义变量 -- property nameLOG_HOME value./logs/ property nameAPP_NAME valuemyapp/ !-- 开发环境开关 -- springProfile namedev property nameLOG_LEVEL valueDEBUG/ /springProfile springProfile nameprod property nameLOG_LEVEL valueINFO/ /springProfile !-- 控制台输出 -- appender nameCONSOLE classch.qos.logback.core.ConsoleAppender encoder pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level %logger{36} - %msg%n/pattern /encoder /appender !-- 更多Appender配置 -- !-- 根日志器 -- root level${LOG_LEVEL:-INFO} appender-ref refCONSOLE/ /root !-- 特定包的日志级别 -- logger namecom.example.service levelDEBUG/ /configurationConsole Appender 配置Console Appender 用于将日志输出到控制台是开发环境中最常用的 Appenderxmlappender nameCONSOLE classch.qos.logback.core.ConsoleAppender encoder pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/pattern /encoder !-- 过滤器只输出INFO及以上级别 -- filter classch.qos.logback.classic.filter.ThresholdFilter levelINFO/level /filter /appenderFile Appender 与滚动策略生产环境中通常需要将日志输出到文件并使用滚动策略防止文件过大xml!-- 滚动文件输出按天 -- appender nameFILE classch.qos.logback.core.rolling.RollingFileAppender file${LOG_HOME}/${APP_NAME}.log/file rollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicy !-- 每天生成一个文件 -- fileNamePattern${LOG_HOME}/archive/%d{yyyy-MM-dd}/${APP_NAME}.%i.log.gz/fileNamePattern !-- 保留30天 -- maxHistory30/maxHistory !-- 单个文件最大100MB -- timeBasedFileNamingAndTriggeringPolicy classch.qos.logback.core.rolling.SizeAndTimeBasedFNATP maxFileSize100MB/maxFileSize /timeBasedFileNamingAndTriggeringPolicy /rollingPolicy encoder pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/pattern /encoder /appender日志级别配置Logback 支持多个日志级别合理配置级别对系统性能和可观测性至关重要xml!-- 根日志器设置 -- root level${LOG_LEVEL:-INFO} appender-ref refCONSOLE/ appender-ref refFILE/ /root !-- 特定包/类级别设置 -- !-- 特定日志器将 com.example.service 包的日志级别设为 DEBUG且日志仅输出到文件不传递给根日志器避免控制台重复输出 -- logger namecom.example.service levelDEBUG additivityfalse appender-ref refFILE / /logger !-- 特定日志器将 org.springframework 包的日志级别设为 WARN减少不必要的日志输出 -- logger nameorg.springframework levelWARN /在这个配置中绝大多数日志遵循根的INFO级别设置。唯独com.example.service包下的日志可以输出DEBUG级别及以上的内容并且这些调试信息只写入文件不会出现在控制台因为additivityfalse。所有来自org.springframework包的日志只有WARN和ERROR级别才会被记录。根日志器 (root) 和特定包/类日志器 (logger) 的设置是日志配置的两个核心层面主要在于作用和范围的区别特性根日志器 (root)特定包/类日志器 (logger)作用范围全局默认。影响所有未被特定logger明确配置的日志记录器。局部特定。仅影响通过name属性指定的包或类及其子包/子类。配置目的设置应用程序的基础日志级别和输出策略。为特定模块提供更精细的日志控制如更详细或更严格的级别。继承性是所有日志器层次的根节点其他日志器默认继承其配置。从其父日志器可能是根或其他上层日志器继承未被自身覆盖的设置。常用级别生产环境常设为INFO或WARN开发环境可设为DEBUG。根据需求灵活设置如将关注模块设为DEBUG将嘈杂的第三方库设为ERROR。Logback 支持的日志级别从低到高依次为TRACE最细粒度的信息通常只在开发过程中使用DEBUGlogger.debug信息INFOlogger.info 信息WARNlogger.warn 信息ERRORlogger.error 信息高级特性与性能优化Logback 提供了多种高级功能可以满足复杂场景下的日志需求。MDCMapped Diagnostic ContextMDC 用于在日志中添加上下文信息如请求 ID、用户 ID非常适合分布式系统跟踪