目录
优质文章
一、日志体系
二、日志门面 Facade
三、日志实现 Impl
四、最佳组合
带你掌握Java各种日志框架 - 蚂蚁小哥 - 博客园
一文带你彻底掌握Log4j2 - 蚂蚁小哥 - 博客园
sl4j是目前常用的日志门面,logback是目前常用的日志框架。
企业级推荐组合
【1】SLF4J + Logback
适用: Spring Boot 默认组合 ,适合大多数企业应用,配置简单且性能稳定
【2】SLF4J + Log4j2
适用: 高性能需求场景,如金融、大数据等领域
桥接 Bridge
转换已有的日志 API 到另一个门面/实现,门面 → 门面 或 API → 门面 。可以出现多个桥接,但是避免形成循环,比如A桥接B,同时B桥接A。使用桥接组件时 必须移除原始 API 的实现类。
依赖名称 | 桥接来源 → 目标 | 用途说明 |
---|---|---|
jcl-over-slf4j |
Commons Logging → SLF4J |
把 JCL 的日志调用转发到 SLF4J |
log4j-over-slf4j | Log4j 1.x → SLF4J |
把 Log4j 1 的 API 调用转发到 SLF4J |
jul-to-slf4j | JUL → SLF4J |
把 JDK Logging 转发到 SLF4J |
绑定Binding
日志门面在运行时“绑定”到某一个具体的日志实现库,门面 → 实现,所有日志调用最终都交给它处理。一个门面只能绑定到一个实现。一般都实现“绑定 + 实现”的全部逻辑(除了Log4j 2)。
依赖名称 | 是否内置实现 | 说明 |
---|---|---|
logback-classic | ✅ 是 | 标准做法 |
slf4j-simple | ✅ 是 | 自带一个非常简单的实现(SimpleLogger ),日志打印到控制台,适合学习和测试 |
slf4j-jdk14 | ✅ 是 | 内部使用 JDK 的 java.util.logging |
slf4j-nop | ✅ 是 | 提供空实现,日志调用直接静默丢弃 |
slf4j-log4j12 | ✅ 是 | Log4j 1 自带绑定和实现 |
log4j-slf4j-impl | ❌ 否 | 只是桥接器,需额外加 Log4j 2 的核心依赖 |
特性/维度 | JCL | SLF4J |
---|---|---|
全称 | Jakarta Commons Logging | Simple Logging Facade for Java |
默认行为 | 默认绑定到 JUL (Java Util Logging) | 默认使用 NOPLogger(空实现) |
依赖机制 | 动态绑定,运行时通过 反射机制 查找 | 静态绑定,运行时依赖 类路径中的实现 jar 包 |
接口设计 | 接口 宽泛笨重,不支持参数化,易出现性能问题 | 支持 {} 占位符参数化日志,避免字符串拼接,提高性能 |
上下文支持 | 不支持 MDC(Mapped Diagnostic Context) | 支持 MDC,方便在多线程/微服务环境中传递 上下文信息 |
框架兼容性 | 容易出现 类加载冲突(特别是与某些应用服务器) | 设计更清晰,避免类冲突,兼容性更好 |
生态现状 | 逐渐被淘汰,维护较弱 | 现代 Java 项目标准,Spring Boot 等主流框架默认集成 |
实现类型 | JCL | SLF4J |
---|---|---|
JUL | 默认绑定,无需额外依赖 | slf4j-jdk14 |
Log4j | 添加 log4j 依赖,直接调用 |
slf4j-log4j12 |
Logback | 不支持,需 桥接到 SLF4J | logback-classic (Spring Boot 默认实现) |
简单输出 | 内置 SimpleLog |
slf4j-simple |
禁用日志 | 无内建支持 | slf4j-nop |
依赖引入
commons-logging
commons-logging
1.2
log4j
log4j
1.2.17
org.slf4j
slf4j-api
1.7.36
ch.qos.logback
logback-classic
1.2.11
具体使用
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.LoggerFactory;
import java.util.logging.*;
public class LogDemo {
private static final Logger log=Logger.getLogger("LogDemo");
private static final Log log1 = LogFactory.getLog(LogDemo.class);
private static final org.slf4j.Logger log2= LoggerFactory.getLogger(LogDemo.class);
public static void main(String[] args) {
log.info("【原生 jul】 "+ log.getClass().getName());
log1.info("【门面 jcl】 "+ log1.getClass().getName());
log2.info("【门面 slf4j】 "+ log2.getClass().getName());
}
}
结果
补充:log4j 需要在src/main/resources/log4j.properties/log4j2.properties中配置属性
特性 / 框架 | JUL | Log4j 1.x | Logback | Log4j 2.x |
---|---|---|---|---|
所属组织 | Oracle(JDK 内置) | Apache 基金会 | QOS.ch(由 Log4j 原作者开发) | Apache 基金会 |
是否内置 | ✅ JDK 自带 | ❌ 需引入依赖 | ❌ 需引入依赖 | ❌ 需引入依赖 |
首次发布年代 | 2002 年(JDK 1.4) | 2001 年 | 2006 年 | 2012 年(对 Log4j 1.x 的重构) |
设计是否现代化 | ❌ 老旧设计 | ❌ 已弃用 | ✅ 现代化架构 | ✅ 现代 + 高性能架构 |
推荐搭配门面 | 可搭配 SLF4J(需桥接) | 可搭配 JCL / SLF4J | ✅ 默认 SLF4J 门面 | ✅ 推荐配合 SLF4J |
日志级别(默认) | SEVERE, WARNING, INFO 等 | FATAL, ERROR, WARN 等 | TRACE ~ ERROR(支持 TRACE) | TRACE ~ FATAL(全级别) |
性能 | ⚠ 中等,异步支持差 | ❌ 性能差,IO阻塞 | ✅ 性能较好 | ✅✅ 非常优秀,异步 + 低GC |
配置文件支持 | .properties |
.properties / .xml |
.xml / .groovy / .json |
.xml / .json / .yaml / .properties |
动态配置加载 | ❌ 不支持 | ⚠ 部分支持 | ✅ 支持热加载 | ✅✅ 热加载 + 自动扫描 |
输出格式定制性 | ⚠ 一般 | ✅ 支持自定义 | ✅✅ 非常灵活(支持颜色等) | ✅✅ 强大模板 + JSON 格式 |
异步日志支持 | ❌ 无 | ❌ 无 | ✅ 内置 AsyncAppender |
✅✅ 原生异步架构(Disruptor) |
SLF4J 兼容性 | ✅ 可桥接 | ✅ 可桥接 | ✅ 默认实现 | ✅ 可绑定至 SLF4J |
是否仍在维护 | ✅ JDK 继续支持 | ❌ 已停止维护 | ✅ QOS.ch 仍在维护 | ✅ 官方持续维护 |
Spring Boot 支持 | ⚠ 可配置启用(非默认) | ❌ 弃用 | ✅ 默认日志实现(Starter 依赖) | ⚠ 需排除 Logback 并配置手动引入 |
package com.epi.web.log;
import com.epi.one.basic.log.WinHandler;
import java.io.IOException;
import java.util.logging.*;
public class JulLogger {
private static final Logger log = Logger.getLogger("JulLogger");
public static void main(String[] args) throws IOException {
for (int i = 0; i < 4; i++) {
julLog(i);
}
}
private static void julLog(Integer handleCase) throws IOException {
Handler handler = switch (handleCase) {
case 0 -> new ConsoleHandler();
case 1 -> new FileHandler("src/main/resources/txt/log.txt", false);
case 2 -> new SocketHandler("localhost", 8088); //开端口监听
case 3 -> new WinHandler(); // 输出到GUI JTextArea
default -> throw new IllegalArgumentException("Unsupported case: " + handleCase);
};
handler.setLevel(Level.ALL);
log.setUseParentHandlers(false); // 关闭默认的控制台 Handler
log.addHandler(handler); // 使用自定义的控制台 Handler
log.setLevel(Level.ALL);
log.severe("SEVERE: This is an error message");
log.warning("WARNING: This is a warning message");
log.info("INFO: This is an info message");
log.config("CONFIG: This is a config message");
log.fine("FINE: This is a fine message");
log.finer("FINER: This is a finer message");
log.finest("FINEST: This is a finest message");
}
}
log4j
log4j
1.2.17
package com.epi.web.log;
import org.apache.log4j.Logger;
public class Log4jLogger {
private static final Logger log = Logger.getLogger(Log4jLogger.class);
public static void main(String[] args) {
System.out.println(log.getClass());
log.fatal("FATAL: 极其严重的错误");
log.error("ERROR: 错误信息");
log.warn("WARN: 警告信息");
log.info("INFO: 一般信息");
log.debug("DEBUG: 调试信息");
log.trace("TRACE: 跟踪信息");
}
}
无法脱离Slf4j使用
org.slf4j
slf4j-api
2.0.16
ch.qos.logback
logback-classic
1.5.16
package com.epi.web.log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogbackLogger {
private static final Logger log = LoggerFactory.getLogger(LogbackLogger.class);
public static void main(String[] args) {
log.error("ERROR: 错误");
log.warn("WARN: 警告");
log.info("INFO: 信息");
log.debug("DEBUG: 调试");
log.trace("TRACE: 跟踪");
}
}
org.apache.logging.log4j
log4j-api
2.17.1
org.apache.logging.log4j
log4j-core
2.17.1
package com.epi.web.log;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4j2Logger {
private static final Logger log = LogManager.getLogger(Log4j2Logger.class);
public static void main(String[] args) {
System.out.println(log.getClass());
log.fatal("FATAL: 极其严重的错误");
log.error("ERROR: 错误信息");
log.warn("WARN: 警告信息");
log.info("INFO: 一般信息");
log.debug("DEBUG: 调试信息");
log.trace("TRACE: 跟踪信息");
}
}
SLF4J | Impl | 关键依赖 | 配置文件 | 备注说明 |
---|---|---|---|---|
1.7.x | Logback 1.2.x |
logback-classic , logback-core |
logback.xml |
经典稳定组合 广泛用于 Spring Boot 2.x 项目 |
2.0.x | Logback 1.4.x / 1.5.x |
|
同上/可无 | 新版组合,面向 SLF4J 2.x 推荐Spring boot新项目使用 |
2.0.x | Log4j 2.x |
|
log4j2.xml |
新版组合,面向 SLF4J 2.x 推荐需要高性能的项目使用 |
文件名
框架 | 默认配置文件位置 | 支持格式 |
---|---|---|
Logback | classpath:logback.xml |
.xml , .groovy , .properties (不推荐) |
Log4j 2 | classpath:log4j2.xml |
.xml , .json , .yaml , .properties |
常见XML标签
功能点 | Logback | Log4j 2 |
---|---|---|
顶级标签 |
|
|
Appender |
|
|
Logger |
|
|
Root Logger |
|
|
Layout 格式 |
|
|
异步日志 |
|
|
…… |
// java设置
MDC.put("key", "value");
// xml使用
%X{key}
package com.epi.web.log;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
@Slf4j
public class MDCDemo {
public static void mdcTest() {
MDC.put("requestId", "REQ123456");
log.info(log.getClass()+" 处理请求开始"); // dev logback + prd log4j2
// 业务代码
MDC.clear(); // 清理,避免内存泄漏
}
}