Hello,大家好!我是唐叔,今天给大家带来的是有关Log4j的使用介绍,希望读完本文章能加深你对Log4j的理解。
一、Log4j介绍
Log4j 是一款功能强大的工业级 Java 日志框架,能够高效处理各类日志记录任务,使开发者可以更专注于业务逻辑的实现。

其主要功能包括:
-
丰富日志内容:自动附加时间戳、文件名、类与方法名称、行号、主机信息、日志级别等上下文信息;
-
灵活格式化消息:支持通过预定义的布局(如 CSV、JSON 等)对日志消息进行结构化格式化;
-
多目标输出:可以将日志写入多种终端,包括控制台、文件、套接字、数据库及消息队列等;
-
精细化过滤:可根据严重级别、内容关键字等条件过滤待输出的日志,提升有效信息密度。
二、Log4j基本使用
使用log4j,就三步骤:引入组件、撰写配置文件、使用组件。
2.1 引入组件
xml
<dependencies>
<!-- Log4j核心依赖 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version> <!-- 建议使用最新稳定版本 -->
</dependency>
<!-- Log4j API -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
</dependencies>
PS:使用log4j,需要同时引入API和对应的实现模块。
2.2 编写配置文件
xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Properties>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
</Properties>
<Appenders>
<!-- 控制台输出 -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${LOG_PATTERN}"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
PS:配置文件的命名必须是以log4j2为前缀,如log4j2.xml、log4j2-test.xml等,且需要放在classpath根目录下(通常是
src/main/resources/
)
2.3 使用组件
java
package cn.uil.demo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class MyClass {
// 获取Logger实例
private static final Logger logger = LogManager.getLogger(MyClass.class);
public void myMethod() {
// 记录不同级别的日志
logger.trace("这是一条TRACE级别的日志");
logger.debug("这是一条DEBUG级别的日志");
logger.info("这是一条INFO级别的日志");
logger.warn("这是一条WARN级别的日志");
logger.error("这是一条ERROR级别的日志");
logger.fatal("这是一条FATAL级别的日志");
// 带参数的日志
String name = "张三";
int age = 25;
logger.info("用户信息:姓名={}, 年龄={}", name, age);
// 异常日志记录
try {
// 可能抛出异常的代码
int result = 10 / 0;
} catch (Exception e) {
logger.error("计算过程中发生错误", e);
}
}
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.myMethod();
}
}
日志输出如下:
properties
2025-08-26 08:37:16.322 [main] INFO cn.uil.demo.MyClass - 这是一条INFO级别的日志
2025-08-26 08:37:16.324 [main] WARN cn.uil.demo.MyClass - 这是一条WARN级别的日志
2025-08-26 08:37:16.324 [main] ERROR cn.uil.demo.MyClass - 这是一条ERROR级别的日志
2025-08-26 08:37:16.324 [main] FATAL cn.uil.demo.MyClass - 这是一条FATAL级别的日志
2025-08-26 08:37:16.325 [main] INFO cn.uil.demo.MyClass - 用户信息:姓名=张三, 年龄=25
2025-08-26 08:37:16.325 [main] ERROR cn.uil.demo.MyClass - 计算过程中发生错误
java.lang.ArithmeticException: / by zero
at cn.uil.demo.MyClass.myMethod(MyClass.java:27) [classes/:?]
at cn.uil.demo.MyClass.main(MyClass.java:35) [classes/:?]
三、Log4j进阶使用
如果你只是想对 log4j 有基本的了解,上述内容足以。如果想要进一步,可以继续往下阅读。
3.1 Log4j日志信息增强
和使用 System.out.print("log data")
相比,使用 Log4j 比较直接的差别莫过于能获取到更多信息,比如日志打印时间记录、日志分级等。
1)日志级别
日志级别是预定义的枚举值,用于表示一条日志信息的重要性或严重性。它们有两个关键特性:
- 有序性:级别有高低之分,顺序是固定的。
- 门槛性 :Logger 只会输出不低于其当前设置级别的日志信息。这条规则是理解日志级别的重中之重。
Log4j 2 提供了以下标准级别,其顺序和典型用途如下:
级别 | 数值 | 含义与用途 | 示例 | 生产环境建议 |
---|---|---|---|---|
ALL | Integer.MIN_VALUE |
最低级别,打开所有日志记录。主要用于配置,而不是在代码中使用。 | 关闭 | |
TRACE | 600 | 追踪信息 。比 DEBUG 更细致、更冗长,用于追踪复杂的程序流,如每个循环内的状态。 |
TRACE - Entering method calculate(), loop i=1, value=5 |
关闭 |
DEBUG | 500 | 调试信息。详细的系统运行信息,对调试应用程序非常有帮助,如输入参数、中间结果、变量值。 | DEBUG - Parameters: userId=123, action=login |
通常关闭 |
INFO | 400 | 信息性消息 。记录应用程序正常运行的关键业务节点和状态。用于回答"系统正在做什么"。 | INFO - User [admin] logged in successfully. INFO - Order [1001] has been shipped. |
打开 |
WARN | 300 | 警告 。表明发生了不常见 但非错误的情况。应用程序仍在正常运行,但未来可能引发错误,需要关注。 | WARN - Cache size is approaching the limit (90%). WARN - API response was slower than expected (2000ms). |
打开 |
ERROR | 200 | 错误 。表明发生了错误事件 ,影响了当前操作或请求(如保存失败、连接断开),但应用程序整体可能仍在运行。需要尽快调查修复。 | ERROR - Failed to connect to database. Retrying... ERROR - Payment processing failed for order [1001]. |
打开 |
FATAL | 100 | 致命错误 。表明发生了非常严重的错误 ,可能导致应用程序完全崩溃或无法继续运行。 | FATAL - Critical configuration file is missing. Shutting down. FATAL - JVM is running out of memory. |
打开 |
OFF | Integer.MAX_VALUE |
最高级别,关闭所有日志记录。主要用于配置。 | 关闭 |
级别高低顺序 :ALL
< TRACE
< DEBUG
< INFO
< WARN
< ERROR
< FATAL
< OFF
使用示例说明:
假设我们在配置文件中将 Root Logger 的级别设置为 WARN
:
xml
<Root level="WARN">
<AppenderRef ref="Console"/>
</Root>
那么在代码中调用不同方法时,会发生以下情况:
java
logger.trace("This is a trace message."); // TRACE(600) < WARN(300) -> **不输出**
logger.debug("This is a debug message."); // DEBUG(500) < WARN(300) -> **不输出**
logger.info("This is an info message."); // INFO(400) < WARN(300) -> **不输出**
logger.warn("This is a warning!"); // WARN(300) == WARN(300) -> **输出**
logger.error("This is an error!"); // ERROR(200) > WARN(300) -> **输出**
logger.fatal("This is a fatal error!"); // FATAL(100) > WARN(300) -> **输出**

环境配置建议:
环境 | 推荐级别 | 原因 |
---|---|---|
本地开发 | DEBUG |
需要最详细的信息来调试和开发功能。 |
测试环境 | DEBUG / INFO |
需要详细信息来排查测试中发现的问题。 |
生产环境 | INFO 或 WARN |
平衡可观察性和性能。INFO 记录关键业务流程;WARN 只记录警告和错误,日志量最小,性能最好。 |
线上排查问题 | 动态调整为 DEBUG |
当生产环境出现疑难问题时,可以通过管理工具(如Spring Boot Actuator)临时 将特定Logger的级别调为DEBUG 来抓取详细信息,排查完后改回。 |
2)日志格式
Log4j 的核心功能是将日志信息按照用户指定的格式输出到指定的目的地(控制台、文件等)。这个格式就是通过 布局(Layout) 来定义的,其中最常用、最灵活的是 PatternLayout
。
PatternLayout
允许通过一个"转换模式"字符串(即 pattern)来定义日志输出的格式。
转换说明符 :以
%
开头,用于插入特定的日志事件数据,如日期、日志级别、类名等。格式通常为%{格式}{参数}
,例如%d{HH:mm:ss.SSS}
,%logger{36}
。
以下是一些最常用和重要的转换说明符:
说明符 | 含义与作用 | 示例输出 |
---|---|---|
%d{pattern} |
日期/时间 。{pattern} 指定日期格式,遵循 Java SimpleDateFormat 规则。 |
%d{yyyy-MM-dd HH:mm:ss.SSS} -> 2023-10-27 14:35:21.123 |
%p / %level |
日志级别。输出日志事件的级别。 | DEBUG , INFO , WARN , ERROR |
%t |
线程名。输出生成日志事件的线程名称。 | main , http-nio-8080-exec-1 |
%c / %logger |
Logger 名称 。通常是发出日志请求的类名。{precision} 可简化包名。 |
%c{1} 输出类名 (Main ),%c 输出全限定类名 (com.example.Main ) |
%M |
方法名 。输出发出日志请求的方法名。注意:获取方法名有性能开销,生产环境慎用。 | doGet , main |
%L |
行号 。输出发出日志请求的代码行号。同样有性能开销,生产环境慎用。 | 123 |
%m / %msg / %message |
应用程序消息。输出应用程序提供的日志内容。 | User login successfully. |
%n |
平台相关的换行符 。在 Windows 上是 \r\n ,在 Unix/Linux 上是 \n 。 |
|
%X |
输出和当前线程关联的 MDC (Mapped Diagnostic Context) 内容 。%X{key} 输出指定 key 的值。 |
%X{requestId} -> rId-12345 |
%throwable |
输出与日志事件关联的异常堆栈跟踪。如果不存在异常,则不输出任何内容。 | java.io.FileNotFoundException: ... |
%highlight |
高亮显示。通常与其他模式组合,根据日志级别为内容着色。需要支持 ANSI 颜色的终端。 | %highlight{%p} 会让 ERROR 显示为红色 |
%r |
相对时间。输出从应用程序启动到日志事件创建所经过的毫秒数。 | 15234 (毫秒) |
%F |
文件名。输出发出日志请求的源代码文件名。 | Main.java |
常用格式示例
- 标准开发/调试格式:这种格式信息非常全,便于调试,但因为包含了方法名(
%M
)和行号(%L
),性能有损耗,不建议在生产环境使用。
properties
%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}.%M(%L) - %msg%n
说明:
%-5level
:-5
表示左对齐并固定宽度为5个字符,这样各级别(INFO, DEBUG, ERROR)就能对齐,更美观。
- 生产环境格式:生产环境通常更关心上下文(时间、级别、线程、Logger名)和业务消息,避免使用高开销的
%M
和%L
。
properties
%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
- 高亮模式:在 IntelliJ IDEA 或 Terminal 等支持 ANSI 颜色的控制台中,使用
%highlight
可以让日志级别更加醒目。
properties
%highlight{%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n}{FATAL=red blink, ERROR=red, WARN=yellow, INFO=green, DEBUG=cyan, TRACE=white}

这里以测试环境模式为示例,高亮模式貌似社区版IDEA不支持...
补充内容:环境差异化配置
核心机制: Log4j 2 在启动时,会按照一个明确的顺序查找配置文件。它允许在文件名中包含环境变量 或系统属性 ,从而实现环境的自动切换。常见的环境差异化配置有:log4j2-dev.xml
(开发环境) 、log4j2-test.xml
(测试环境)等。
- 通过 JVM 参数指定环境
这种方式通过在启动应用时传递一个 JVM 参数来明确指定要使用哪个环境的配置。
-
创建不同环境的配置文件 在你的项目资源目录(如
src/main/resources
)下创建多个配置文件:log4j2-dev.xml
- 开发环境配置(级别为DEBUG
, 输出到控制台)[代码略]
log4j2-pro.xml
- 生产环境配置(级别为INFO
, 输出到文件和时间滚动归档)[代码略]
-
在启动命令中指定环境 通过 JVM 参数
-Dlog4j.configurationFile
来指定激活哪个文件。参数的值就是配置文件的完整名称。-
在 IDEA 中启动(开发):
-
编辑运行配置(Edit Configurations...)
-
在
VM options
中添加:-Dlog4j.configurationFile=log4j2-dev.xml
-
-
在服务器上启动 :
java -Dlog4j.configurationFile=log4j2-pro.xml -jar myapplication.jar
-

在 IDEA 中没显示
VM options
,可以点击Modify options
,勾选Add VM options
即可。
3.2 Log4j日志结构化
Log4j日志结构化,主要依赖于 JSON Template Layout
。它允许你使用 Jackson JSON 处理器和 JSON 模板,将日志事件(LogEvent)高度定制化地序列化为 JSON 对象 ,而不是一行行的文本。与传统 PatternLayout
相比,结构化数据 (Structured Data),日志被输出为键值对(JSON),便于日志收集系统(如ELK)直接摄取和索引,无需复杂的解析(Grok)规则。
使用方式
- 添加依赖
xml
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-layout-template-json</artifactId>
<version>2.17.1</version> <!-- 请使用与log4j-core相同的版本 -->
</dependency>
- 配置 (log4j2.xml)
xml
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<JsonTemplateLayout eventTemplateUri="classpath:LogstashJsonEventLayoutV1.json"/>
</Console>
</Appenders>
LogstashJsonEventLayoutV1.json 是内置的json格式模板,也可以配置自定义json模板,然后这里进行替换即可。
- 使用效果演示

3.3 Log4j日志归档
Log4j 通过 Appender 组件模型来实现将日志输出到控制台、文件、套接字、数据库、队列等各种位置。
以将日志同时输出到控制台和文件为例,调整 log4j2.xml 文件,增加RollingFile配置。
xml
<RollingFile name="RollingFile"
fileName="logs/app.log"
filePattern="logs/app-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<Policies>
<!-- 基于时间的触发策略:每天轮转一次 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<!-- 基于大小的触发策略:如果文件超过10MB,也触发轮转 -->
<SizeBasedTriggeringPolicy size="10 MB"/>
</Policies>
<!-- 保留最近7天的日志,最多15个文件,超过的自动删除 -->
<DefaultRolloverStrategy max="15">
<Delete basePath="logs" maxDepth="1">
<IfFileName glob="app-*.log.gz"/>
<IfLastModified age="7D"/>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
效果演示

日志也可以写入队列等,额外引入日志扩展组件即可,这里就不作展开了。
补充内容:日志异步
Log4j 使用 Async 组件实现日志异步打印。
以日志异步输出到文件为例,调整 log4j2.xml 文件,在 Appenders 添加 Async 组件。
xml
<Async name="AsyncFile" bufferSize="8192">
<!-- 引用同步的文件Appender -->
<AppenderRef ref="RollingFile"/>
<!-- 可选:如果异步队列满了,可以指定一个备用的同步Appender(如控制台)来接收日志,避免丢失 -->
<!-- <AppenderRef ref="Console"/> -->
</Async>
效果演示

3.4 Log4j日志过滤
Log4j 的 过滤器(Filter) 组件可以在日志事件进入 Appender 或 Logger 之前对其进行拦截和判断,决定是接受、拒绝还是忽略该日志事件。例如可以使用 RegexFilter 用于过滤敏感信息,不做日志打印。
xml
<!-- 过滤掉包含"password"一词的日志(忽略大小写) -->
<RegexFilter regex=".*password.*" onMatch="DENY" onMismatch="NEUTRAL" useRawMsg="true"/>
效果演示

补充内容:敏感字打印替换
对于复杂的数据脱敏(如过滤JSON字符串中的特定字段),RewriteAppender
允许你在将日志事件传递给最终Appender之前,先对其进行修改。
- 自定义敏感信息替换类
java
// 使用 @Plugin 注解注册插件
@Plugin(name = "RegexReplaceRewritePolicy",
category = Core.CATEGORY_NAME,
elementType = "rewritePolicy",
printObject = true)
public final class RegexReplaceRewritePolicy implements RewritePolicy {
private final Pattern regexPattern;
private final String replacement;
// 构造函数
private RegexReplaceRewritePolicy(String regex, String replacement) {
this.regexPattern = Pattern.compile(regex);
this.replacement = replacement;
}
// 重写 rewrite 方法,实现正则替换逻辑
@Override
public LogEvent rewrite(LogEvent event) {
// 获取原始日志消息
String originalMessage = event.getMessage().getFormattedMessage();
// 执行正则替换
String modifiedMessage = regexPattern.matcher(originalMessage).replaceAll(replacement);
// 如果消息未被修改,直接返回原事件
if (originalMessage.equals(modifiedMessage)) {
return event;
}
// 创建并返回一个新的 LogEvent,包含修改后的消息
return new Log4jLogEvent.Builder(event)
.setMessage(new SimpleMessage(modifiedMessage))
.build();
}
// 使用 @PluginFactory 注解标记工厂方法,用于从配置创建策略实例
@PluginFactory
public static RegexReplaceRewritePolicy createPolicy(
@PluginAttribute("regex") String regex,
@PluginAttribute("replacement") String replacement) {
return new RegexReplaceRewritePolicy(regex, replacement);
}
}
- 配置log4j2.xml 文件:在Appenders中声明
xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<!-- 1. 定义最终的输出目标(控制台) -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level - %msg%n"/>
</Console>
<!-- 2. 定义重写器,进行敏感信息脱敏 -->
<Rewrite name="RewriteSensitiveData">
<!-- 指定脱敏后的日志输出到哪个Appender -->
<AppenderRef ref="Console"/>
<!-- 使用RegexReplace重写策略 -->
<RegexReplaceRewritePolicy regex="(?i)(password|pwd)=[^&\s]+" replacement="$1=***"/>
</Rewrite>
</Appenders>
<Loggers>
<Root level="INFO">
<!-- 关键:将Root Logger指向重写器,而不是直接的Console -->
<AppenderRef ref="RewriteSensitiveData"/>
</Root>
</Loggers>
</Configuration>
效果演示

四、Log4j深入理解
下面的内容是唐叔对 Log4j 的一些理解,如果你只是掌握 Log4j 的使用,下述内容就可以直接略过啦。
4.1 Log4j2 架构&配置文件解读
通过上述的配置,其实大家可以明确地体会到 Log4j.xml 文件在 Log4j 的使用中十分重要。
在理解 Log4j.xml 配置文件前,我们先了解下 Log4j 的代码架构。下图是 Log4j 官网的架构图。

4.1.1 Log4j 整体架构概述
Log4j 的架构主要由以下几个核心部分组成:
-
LoggerContext:日志系统的入口和上下文环境。
-
Configuration:配置信息的容器,包括 Appender、LoggerConfig、Filter 等。
-
Logger:用户直接使用的日志记录接口。
-
LoggerConfig:配置每个 Logger 的行为(如级别、Appender、Filter)。
-
Appender:定义日志输出的目的地(如文件、控制台、网络)。
-
Layout:定义日志输出的格式。
-
Filter:在不同级别上过滤日志事件。
-
StrSubstitutor / Interpolator / StrLookup:处理配置中的变量替换(如
${env:USER}
)。
4.1.2 运作机理概述
-
用户代码调用 Logger:
logger.info("This is a log message");
-
Logger 委托给 LoggerConfig:
-
Logger 本身不处理日志,而是委托给其对应的 LoggerConfig。
-
LoggerConfig 根据配置决定是否处理该日志(基于 Level 和 Filter)。
-
-
LoggerConfig 调用 AppenderControl:
-
每个 LoggerConfig 包含一个或多个 AppenderControl。
-
AppenderControl 是对 Appender 的封装,可能附加 Filter。
-
-
Appender 输出日志:
-
Appender 使用 Layout 格式化日志事件。
-
最终输出到目的地(文件、控制台、数据库等)。
-
-
Filter 机制:
-
Filter 可以在四个级别上设置:Configuration、LoggerConfig、AppenderControl、Appender。
-
每个 Filter 决定是否接受、拒绝或中立处理 LogEvent。
-
-
变量替换:
- 使用
StrSubstitutor
→Interpolator
→StrLookup
链解析${...}
表达式。
- 使用
4.1.3 Log4j2.xml理解
当用户调用 Logger 时,Log4j 会读取配置文件信息,根据配置文件来判断如何处理用户的日志打印。
而每个配置文件上的每个标签都有具体的含义,下图是简要的解读:

简单说,Log4j 通过配置驱动 和责任链模式 实现了高度可扩展的日志系统。用户只需与 Logger
交互,而底层的 LoggerConfig
、Appender
、Filter
、Layout
等组件通过配置灵活组合,满足各种日志需求。
4.2 多日志框架混用的统一策略
事实上,Java主流的日志框架,除了 log4j,其实还有 logback、Slf4j等。而大型项目是由很多组件构成,每个组件可能最终使用的日志框架不尽一样。而 Log4j 的开发者其实也考虑到了这一点,利用桥接模式巧妙的解决了多日志框架混用的日志输出混乱问题。下图是 Log4j 官网的多日志框架桥接适配方式图。

项目本身或存在多个模块或组件(Application、Library 1/2/3),使用了不同的日志框架。默认用户调用的都是各个日志框架的API层(SLF4J、JUL、JPL、Log4j API),通过桥接器的方式(SLF4J-to-Log4j
、JUL-to-Log4j
、JPL-to-Log4j
),将其他日志API的调用转发到Log4j API的实现层 Log4j Core,而最终都统一采用 Log4j 的方式进行日志打印输出。
理解了上面的原理,那么日常该如何使用呢,下面是唐叔的一些建议:
-
如果你的项目只使用 Log4j2 ,直接引入
log4j-core
(API实现)和log4j-api
。 -
如果项目中有第三方库使用 SLF4J,引入:
-
log4j-core
-
log4j-api
-
log4j-slf4j-impl
(即图中的SLF4J-to-Log4j
) -
如果项目中存在 SLF4J API的实现,需要同步移除
-
-
如果使用 JUL ,可引入
log4j-jul
桥接器。 -
注意:避免同时引入多个桥接器或日志实现,防止冲突。
好啦,以上就是今天的讲解内容啦,感谢阅读。