Log4j配置的核心在于三件事:定义日志级别、绑定输出端(Appender)、决定日志格式(Layout),推荐直接用log4j2的XML配置,一条配置即可搞定按天滚动和异步写入。
老项目里常常见到log4j.properties,维护起来像在翻旧账本,本文从这套配置说起,再对比log4j2的XML写法,最后落到生产环境的滚动策略和性能调优,你不用从头看文档,照着下面的模块抄就行。
log4j.properties配置详解:老项目为何需要升级?
log4j.properties是Log4j 1.x时代的配置文件,键值对风格,简单直白,但Log4j 1.x早已停止维护,业内专家指出,继续使用它在现在意味着高风险漏洞得不到官方修复,log4j.properties配置详解”表面是学语法,实际上是为了让你能看懂老代码,并计划迁移到log4j2。
两种配置文件的直观区别如下:
- log4j.properties:用
log4j.rootLogger=INFO, stdOut定义根Logger,用log4j.appender.stdOut=org.apache.log4j.ConsoleAppender定义输出端。 - log4j2.properties:键名变成
rootLogger.level和appender.rolling.type,语法不兼容,但能用属性文件驱动log4j2。 - log4j2.xml:目前最常用的写法,结构清晰,支持异步日志和条件过滤。
log4j日志级别怎么设置?五种级别选择指南
日志级别决定了哪些消息能落盘,按从低到高排列:TRACE、DEBUG、INFO、WARN、ERROR、FATAL,级别越低,输出越啰嗦。
在实际项目里,多数情况下这样设:
# log4j 1.x 写法 log4j.rootLogger=INFO, fileAppender
- DEBUG:本地调试时用,配合IDE查看SQL和参数。
- INFO:生产环境默认级别,记录启动、关闭、关键业务流转。
- ERROR:只记录异常和失败,适合告警监控。
- FATAL:通常仅用于进程致命的错误,使用频率很低。
有个常见误区:把根Logger设为DEBUG后,子Logger里写WARN,子包日志会变成WARN,而其他包仍然是DEBUG,因为log4j的继承机制是“子覆盖根”,这是特征,不是Bug。
properties配置里的三个坑
- 键名大小写敏感,
log4j.rootLogger和Log4j.RootLogger是两回事。 - 文件编码默认用平台字符集,中文日志乱码时记得指定
log4j.appender.fileAppender.encoding=UTF-8。 - 路径中的
${user.dir}是相对于进程启动目录,不是项目根目录,部署环境不一样就会“找不到日志文件”。

log4j.properties看似简单,但每个键背后的Appender生命周期和刷新机制都需要理解,这也是为什么log4j2配置教程里,官方更推荐XML。
log4j2配置教程:从XML到异步日志
log4j2的XML配置把Logger、Appender、Layout拆成XML节点,比Properties更直观,下面是一份经过生产验证的最小骨架,你直接复制改路径就好。
log4j2.xml配置的基本骨架
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<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} %-5level %logger - %msg%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100MB"/>
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
- Configuration status:log4j2自身日志输出级别,设为WARN可避免刷屏。
- PatternLayout:定义日志格式,
%msg%n是消息和换行。 - RollingFile:核心滚动文件Appender,按时间和大小两种策略同时触发。
log4j2按天滚动日志配置的两种写法
“按天滚动”是运维最常用的需求,目的是让单日日志独立成文件,方便排查和备份,roll策略有两种主流写法:
纯时间触发
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
配合filePattern="./logs/app-%d{yyyy-MM-dd}.log",每天零点切割,不压缩。
时间+大小双触发
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="500MB"/>
</Policies>
这种策略更保险:白天流量突增,单日文件超过500MB也会触发滚动,避免打开文件时卡顿,此时

filePattern需要加上%i序号,如app-%d{yyyy-MM-dd}-%i.log,否则文件会互相覆盖。
注意:max属性在DefaultRolloverStrategy中控制保留的备份数量,最大值为10代表最多保留10个历史文件,超出后自动删除最老的,这个值要依据磁盘空间调,别随意拍脑袋。
log4j2异步日志配置注意事项
异步日志能降低业务线程的IO阻塞,但配置不当反而丢日志,核心做法是启用AsyncLogger,需要引入disruptor依赖,XML中修改为:
<AsyncLogger name="com.example" level="INFO" includeLocation="false">
<AppenderRef ref="RollingFile"/>
</AsyncLogger>
includeLocation="false":不记录代码行号,性能大幅提升,但查日志时看不到方法名。- Intel下
AsyncLogger默认使用全局队列,多个Logger间会互相影响。
行业共识认为,异步日志能显著降低高吞吐服务的响应延迟,但前提是你接受日志丢失的极小概率,对交易类系统,建议同步写WARN和ERROR,异步写INFO和DEBUG,用ThresholdFilter实现。
生产环境日志格式与性能调优
日志格式不是好看而已,它直接决定排障效率,生产环境里,行日志需要包含时间、线程、级别、类名和消息,常用占位符有:
%d:时间,可配格式如{yyyy-MM-dd HH:mm:ss.SSS}。%t:线程名。%-5level:左对齐级别,占5字符。%logger{36}:类名缩写。%X{traceId}:读取MDC里的TraceId,全链路追踪时必配。%throwable:完整堆栈。
一个推荐格式:
%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} [%X{traceId}] - %msg%n
日志文件备份与清理策略
很多项目只配滚动,不配清理,运行半年后磁盘满,log4j2的DefaultRolloverStrategy提供Delete配置:
<DefaultRolloverStrategy max="30">
<Delete basePath="${baseDir}" maxDepth="1">
<IfFileName glob=".log.gz"/>
<IfLastModified age="7d"/>
</Delete>
</DefaultRolloverStrategy>
max=30:最多30个文件。Delete:删除7天前的压缩文件。basePath:要扫描的目录,必须与filePattern的目录一致。

注意:Delete只能处理不再写入的文件,正在写入的日志文件处于锁定状态,不会被误删。
log4j2配置文件不生效?先从加载顺序排查
配置写了但日志行为没变,这是开发阶段最高频的问题,log4j2有严格的配置加载顺序,按优先级从高到低:
log4j2-test.properties、log4j2-test.yaml、log4j2-test.json、log4j2-test.xmllog4j2.properties、log4j2.yaml、log4j2.json、log4j2.xml- 系统属性
-Dlog4j.configurationFile=路径指定的文件
如果你的log4j2.xml放在resources根目录,且没有test文件,那它一定会被加载,不生效时,先看控制台是否有ERROR StatusLogger报错,再检查项目里是否残留了log4j.properties它会被log4j2的桥接模块误读,产生干扰。
配置了Root Logger为何没有输出
通常是这两个原因:
- 子Logger显式指定了丢日志的Appender,且
additivity="false"切断了向根Logger的传递。 - Filter误伤,比如某个Filter把所有INFO级别都拒绝了。
用-Dlog4j2.debug=true启动,控制台会打印每个Logger和Appender的关联状态,这是最实在的排查手段。
Q&A:log4j配置常见问题解答
log4j2配置文件和log4j.properties能不能共存?
能共存,但不建议,旧项目迁移时,log4j2会优先读取自己的文件,但历史依赖中如果存在log4j-over-slf4j或slf4j-log4j12,类加载顺序会混乱,最好的方式是删掉log4j.properties,只保留一套日志配置。
生产环境log4j2怎么关闭debug日志?
把<Root level="INFO">作为基准,再检查业务代码里是否调用Logger.debug输出敏感参数,如果第三方库的INFO日志太多,用<Logger name="org.apache.http" level="WARN"/>单独压级别,关闭所有DEBUG输出的有效方法是在配置中加入<ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>,放在Appender下即可。
log4j和slf4j是什么关系?
slf4j是日志门面,没有任何实现;log4j2是具体实现,代码里写LoggerFactory.getLogger时,运行时绑定的是log4j2提供的log4j-slf4j-impl依赖,如果绑定错误,无论log4j2配置教程写得多漂亮,日志都走不到Appender里。
