Apache Log4j 2.26.1 集成使用实战详解

从 Maven 依赖引入到三个可运行示例(Console/滚动文件/异步)完整演示 Apache Log4j 2.26.1 的集成使用,全部代码与回显均实测通过。

Apache Log4jLog4jApacheJava日志2026/10/15

Apache Log4j 2.26.1 集成使用实战详解

目标:在 Ubuntu 22.04 上以 Maven 项目集成 Log4j 2.26.1,完成控制台、滚动文件、异步日志三个可运行示例,并掌握 Marker/ThreadContext/Filter 等进阶用法。已在 Ubuntu 22.04(OpenJDK 17)实测通过。

一、环境信息

项目值
操作系统Ubuntu 22.04.5 LTS
系统架构x86_64(amd64)
JDKOpenJDK 17.0.20.1
MavenApache Maven 3.6.3(apt 源)
组件版本Apache Log4j 2.26.1、disruptor 4.0.0
项目目录/opt/log4j-demo
日志输出目录/opt/log4j-demo/logs

表后逐项说明:JDK 17 是 Log4j 2.24+ 的硬性要求;Maven 仅用于依赖管理与编译,3.6.3 即可;实验项目放 /opt/log4j-demo,文件型日志统一输出到其 logs 子目录。

二、依赖引入

2.1 创建 Maven 工程

mkdir -p /opt/log4j-demo/src/main/java/com/example /opt/log4j-demo/src/main/resources

2.2 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>log4j-demo</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>

  <properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-api</artifactId>
      <version>2.26.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>2.26.1</version>
    </dependency>
    <dependency>
      <groupId>com.lmax</groupId>
      <artifactId>disruptor</artifactId>
      <version>4.0.0</version>
    </dependency>
  </dependencies>
</project>

逐项说明:log4j-api 提供编译期接口;log4j-core 提供运行期实现(两者都显式声明,实测依赖树证实 core 不会把 api 传递进来);disruptor 4.0.0 供 AsyncLogger 使用;编译目标 17 与 JDK 匹配。

2.3 拉取依赖并编译

cd /opt/log4j-demo
mvn compile

实测回显(输出节选,实测首尾):

[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< com.example:log4j-demo >-----------------------
[INFO] Building log4j-demo 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] --- resources:3.3.1:resources (default-resources) @ log4j-demo ---
[INFO] Copying 5 resources from src/main/resources to target/classes
[INFO] --- compiler:3.13.0:compile (default-compile) @ log4j-demo ---
[INFO] Compiling 3 source files with javac [debug target 17] to target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

生成运行用 classpath 文件:

mvn dependency:build-classpath -Dmdep.outputFile=/tmp/cp.txt -q
cat /tmp/cp.txt

实测回显:

/root/.m2/repository/org/apache/logging/log4j/log4j-api/2.26.1/log4j-api-2.26.1.jar:/root/.m2/repository/org/apache/logging/log4j/log4j-core/2.26.1/log4j-core-2.26.1.jar:/root/.m2/repository/com/lmax/disruptor/4.0.0/disruptor-4.0.0.jar

说明:classpath 只含三个 jar,验证了"api + core + disruptor"的最小依赖集;后续所有示例都用 java -cp "target/classes:依赖路径" 方式运行,与 IDE/应用服务器的运行模型一致。

三、示例一:控制台日志(级别/Marker/ThreadContext 实测)

3.1 业务代码

package com.example;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.ThreadContext;

public class LevelConsoleDemo {
    private static final Logger logger = LogManager.getLogger(LevelConsoleDemo.class);
    private static final Marker SECURITY = MarkerManager.getMarker("SECURITY");
    private static final Marker AUDIT = MarkerManager.getMarker("AUDIT").setParents(SECURITY);

    public static void main(String[] args) {
        ThreadContext.put("requestId", "req-20260101-0001");
        logger.trace("trace 级别消息,低于 Root/INFO 时不输出");
        logger.debug("debug 级别消息,SQL 参数预览");
        logger.info("info 级别消息,服务启动完成");
        logger.warn("warn 级别消息,磁盘使用率 85%");
        logger.error("error 级别消息,订单 1001 支付超时", new IllegalStateException("payment timeout"));
        logger.fatal("fatal 级别消息,无法连接数据库");
        logger.info(AUDIT, "用户 root 登录成功(AUDIT 继承自 SECURITY)");
        ThreadContext.clearAll();
    }
}

逐项说明:LogManager.getLogger(类) 创建同名 Logger;AUDIT 通过 setParents 挂到 SECURITY 下;ThreadContext.put 写入请求维度键值;error 调用第二参数传异常对象,配合布局的 %throwable 打栈。

3.2 配置文件 log4j2-console.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} [%marker] [req=%X{requestId}] - %msg%n%throwable"/>
      <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
    </Console>
  </Appenders>
  <Loggers>
    <Logger name="com.example" level="DEBUG" additivity="false">
      <AppenderRef ref="Console"/>
    </Logger>
    <Root level="INFO">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

逐项说明:pattern 的 %-5level 左对齐补齐 5 字符;%logger{36} 超长包名缩写;[%marker] 无 Marker 时输出 [];%X{requestId} 取 ThreadContext 键;monitorInterval=30 每 30 秒检测配置变更热加载。

3.3 编译与运行

LC_ALL=C.UTF-8 java -Xms256m -Xmx256m -Dlog4j.configurationFile=src/main/resources/log4j2-console.xml -cp "target/classes:$(cat /tmp/cp.txt)" com.example.LevelConsoleDemo

实测回显:

2026-10-14 16:57:03.122 [main] DEBUG com.example.LevelConsoleDemo [] [req=req-20260101-0001] - debug 级别消息,SQL 参数预览
2026-10-14 16:57:03.126 [main] INFO  com.example.LevelConsoleDemo [] [req=req-20260101-0001] - info 级别消息,服务启动完成
2026-10-14 16:57:03.126 [main] WARN  com.example.LevelConsoleDemo [] [req=req-20260101-0001] - warn 级别消息,磁盘使用率 85%
2026-10-14 16:57:03.127 [main] ERROR com.example.LevelConsoleDemo [] [req=req-20260101-0001] - error 级别消息,订单 1001 支付超时
java.lang.IllegalStateException: payment timeout
        at com.example.LevelConsoleDemo.main(LevelConsoleDemo.java:20)
2026-10-14 16:57:03.128 [main] FATAL com.example.LevelConsoleDemo [] [req=req-20260101-0001] - fatal 级别消息,无法连接数据库
2026-10-14 16:57:03.128 [main] INFO  com.example.LevelConsoleDemo [AUDIT[ SECURITY ]] [req=req-20260101-0001] - 用户 root 登录成功(AUDIT 继承自 SECURITY)

逐项说明:trace 被过滤(Logger DEBUG 级别与 ThresholdFilter 双重拦截);ERROR 行带完整异常栈;AUDIT Marker 显示为 AUDIT[ SECURITY ];运行参数 -Xms256m -Xmx256m 限定堆,另开终端用 jps -v 可见:

4314 LevelConsoleDemo -Xms256m -Xmx256m -Dlog4j.configurationFile=src/main/resources/log4j2-console.xml

四、示例二:滚动文件(RollingFile 实测)

4.1 业务代码

package com.example;

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

public class RollingFileDemo {
    private static final Logger logger = LogManager.getLogger(RollingFileDemo.class);

    public static void main(String[] args) {
        for (int i = 0; i < 200; i++) {
            logger.info("滚动日志测试第 {} 行:订单 1001 支付成功,金额 128.00 元", i);
        }
        logger.info("写入完成,请查看 /opt/log4j-demo/logs 目录");
    }
}

说明:占位符 {} 由布局用 %msg 配合参数替换渲染,比字符串拼接省去无效拼接开销。

4.2 配置文件 log4j2-rolling.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <RollingFile name="RollingFile" fileName="/opt/log4j-demo/logs/app.log"
                 filePattern="/opt/log4j-demo/logs/app-%d{yyyy-MM-dd}-%i.log.gz">
      <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %p %c{1.} [%t] - %m%n"/>
      <Policies>
        <SizeBasedTriggeringPolicy size="10 KB"/>
        <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
      </Policies>
      <DefaultRolloverStrategy max="5"/>
    </RollingFile>
  </Appenders>
  <Loggers>
    <Root level="INFO">
      <AppenderRef ref="RollingFile"/>
    </Root>
  </Loggers>
</Configuration>

逐项说明:fileName 是活动文件;filePattern 是滚动后的命名模板(%i 是当日序号,.gz 后缀触发滚动时自动压缩);SizeBasedTriggeringPolicy size=10 KB 表示单文件超 10KB 滚动;TimeBasedTriggeringPolicy interval=1 按天滚动(与 filePattern 中 %d 粒度一致);DefaultRolloverStrategy max=5 限制当日最多保留 5 个序号文件。

4.3 运行与验证

mkdir -p /opt/log4j-demo/logs
LC_ALL=C.UTF-8 java -Xms256m -Xmx256m -Dlog4j.configurationFile=src/main/resources/log4j2-rolling.xml -cp "target/classes:$(cat /tmp/cp.txt)" com.example.RollingFileDemo
ls -l /opt/log4j-demo/logs/

实测回显:

total 16
-rw-r--r-- 1 root root  492 Oct 14 16:57 app-2026-10-14-1.log.gz
-rw-r--r-- 1 root root  492 Oct 14 16:57 app-2026-10-14-2.log.gz
-rw-r--r-- 1 root root 6321 Oct 14 16:57 app.log

查看归档内容(首尾):

zcat /opt/log4j-demo/logs/app-2026-10-14-1.log.gz | head -2
zcat /opt/log4j-demo/logs/app-2026-10-14-1.log.gz | tail -1
head -2 /opt/log4j-demo/logs/app.log
tail -1 /opt/log4j-demo/logs/app.log

实测回显:

2026-10-14 16:57:13.238 INFO c.e.RollingFileDemo [main] - 滚动日志测试第 0 行:订单 1001 支付成功,金额 128.00 元
2026-10-14 16:57:13.240 INFO c.e.RollingFileDemo [main] - 滚动日志测试第 1 行:订单 1001 支付成功,金额 128.00 元
2026-10-14 16:57:13.249 INFO c.e.RollingFileDemo [main] - 滚动日志测试第 76 行:订单 1001 支付成功,金额 128.00 元
2026-10-14 16:57:13.263 INFO c.e.RollingFileDemo [main] - 滚动日志测试第 154 行:订单 1001 支付成功,金额 128.00 元
2026-10-14 16:57:13.269 INFO c.e.RollingFileDemo [main] - 写入完成,请查看 /opt/log4j-demo/logs 目录

逐项说明:200 行共约 13KB,超过 10KB 阈值滚动两次,序号 1、2 归档压缩(492 字节),活动文件 app.log 保留最后 6321 字节;%c{1.} 输出 com.example 缩写为 c.e.;全部输出经 %d 带毫秒时间戳。

五、示例三:异步日志(AsyncLogger 实测)

5.1 业务代码

package com.example;

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

public class AsyncDemo {
    private static final Logger logger = LogManager.getLogger(AsyncDemo.class);

    public static void main(String[] args) throws Exception {
        long start = System.nanoTime();
        for (int i = 0; i < 500000; i++) {
            logger.info("异步日志性能测试 {}", i);
        }
        long submitMs = (System.nanoTime() - start) / 1_000_000;
        System.out.println("500000 条异步日志提交耗时 " + submitMs + " ms(入队即返回)");
        LogManager.shutdown();
        System.out.println("LogManager.shutdown 完成,日志已全部落盘");
    }
}

说明:AsyncLogger 把"格式化与写盘"交给 Disruptor 消费线程,业务线程只做入队;退出前调用 LogManager.shutdown 确保缓冲排空。

5.2 配置文件 log4j2-async.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <File name="AsyncFile" fileName="/opt/log4j-demo/logs/async.log">
      <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %p [%t] %c{1.} - %m%n"/>
    </File>
  </Appenders>
  <Loggers>
    <AsyncLogger name="com.example.AsyncDemo" level="INFO" includeLocation="false">
      <AppenderRef ref="AsyncFile"/>
    </AsyncLogger>
    <Root level="INFO">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

逐项说明:AsyncLogger 元素与 Logger 同位置声明,name 匹配的 Logger 自动走 Disruptor;includeLocation=false 关闭调用位置采集(取栈开销大,是异步吞吐的关键开关);Root 保持普通同步(非全局异步模式,只对声明的 AsyncLogger 生效)。

5.3 运行与验证

LC_ALL=C.UTF-8 java -Xms256m -Xmx256m -Dlog4j.configurationFile=src/main/resources/log4j2-async.xml -cp "target/classes:$(cat /tmp/cp.txt)" com.example.AsyncDemo

实测回显:

500000 条异步日志提交耗时 5383 ms(入队即返回)
LogManager.shutdown 完成,日志已全部落盘

落盘完整性验证:

wc -l /opt/log4j-demo/logs/async.log
head -2 /opt/log4j-demo/logs/async.log
tail -1 /opt/log4j-demo/logs/async.log

实测回显:

500000 /opt/log4j-demo/logs/async.log
2026-10-14 16:57:38.504 INFO [main] c.e.AsyncDemo - 异步日志性能测试 0
2026-10-14 16:57:43.887 INFO [main] c.e.AsyncDemo - 异步日志性能测试 499999

逐项说明:50 万条全部落盘(wc -l 计数一致),从首条到末条时间跨度约 5.4 秒;业务线程提交完成后立刻打印耗时(5383 ms),说明写入工作全部由后台线程承担;关机钩子保证 JVM 正常退出时缓冲不丢。

六、进阶用法

6.1 精确级别过滤(LevelMatchFilter)

在 Appender 上只放行某一级别(2.26.1 用 LevelMatchFilter,注意 LevelFilter 这个旧元素名已不存在):

<Console name="Console" target="SYSTEM_OUT">
  <PatternLayout pattern="LEVELFILTER %-5level - %msg%n"/>
  <LevelMatchFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>

实测输出(Root 级别 DEBUG 下的程序):

LEVELFILTER WARN  - warn 级别消息,磁盘使用率 85%

说明:与 ThresholdFilter(放行 >= 阈值)不同,LevelMatchFilter 是"等于"语义,onMatch/onMismatch 支持 ACCEPT/NEUTRAL/DENY 三值组合。

6.2 内部状态排查(status=DEBUG)

2026-10-14T17:26:30.661243734Z main DEBUG Apache Log4j Core 2.26 initializing configuration XmlConfiguration[location=/opt/log4j-demo/src/main/resources/log4j2-debug.xml, lastModified=2026-10-14T17:25:02.014Z]
2026-10-14T17:26:30.663621510Z main DEBUG PluginManager 'Core' found 134 plugins

说明:status=DEBUG 时输出的第一行会显示实际加载的配置文件路径与最后修改时间,是验证"配置到底加载了哪份"的实测依据。

6.3 运行期指定配置文件

所有示例都通过 -Dlog4j.configurationFile 显式指定配置,多环境部署时最直观;不指定时按 classpath 的 log4j2.properties/yaml/json/xml 顺序自动发现,都找不到则回退 ERROR 级别默认配置。

七、常见问题(FAQ)

Q1:mvn compile 报 invalid target release: 17? A:编译机的 JDK 低于 17。确认 java -version 输出 17 开头(Ubuntu 22.04:apt-get install openjdk-17-jdk-headless),并确认 JAVA_HOME 指向 17。

Q2:运行时报 NoClassDefFoundError: org/apache/logging/log4j/Logger? A:classpath 缺 log4j-api。本文运行方式用 dependency:build-classpath 产出的 /tmp/cp.txt 拼进 -cp,直接手写 -cp target/classes 就会丢依赖。

Q3:控制台中文乱码问号? A:JVM 在管道输出时按系统 locale 编码 stdout。给 java 命令前加 LC_ALL=C.UTF-8 LANG=C.UTF-8(实测解决);文件型 Appender 不受影响,因为文件编码默认 UTF-8。

Q4:RollingFile 没有滚动? A:检查三点:Policies 里 SizeBasedTriggeringPolicy 的 size 是否达到(实测 10 KB);filePattern 里是否含 %i(大小滚动序号);写入量是否真的超阈值。本文 200 行约 13KB 滚出两个 gz 归档。

Q5:异步日志丢了最后几条? A:AsyncLogger 的缓冲需要排空。应用退出前调用 LogManager.shutdown()(实测调用后 wc -l 恰好 500000 行);或注册 JVM 关机钩子。异常 kill -9 属不可恢复场景。

Q6:includeLocation=true 后异步吞吐骤降? A:采集调用位置要抓当前线程栈,异步模式下开销被放大。生产建议 includeLocation="false"(本文异步配置即如此),确需位置信息时仅对低频 Logger 开启。

Q7:怎么验证 JVM 堆参数真的生效? A:jps -v 查看进程参数,实测回显包含 -Xms256m -Xmx256m:4314 LevelConsoleDemo -Xms256m -Xmx256m ...。也可 ps -ef | grep [j]ava 看完整命令行。

Q8:占位符 {} 与字符串拼接怎么选? A:所有可能被级别过滤掉的日志都用参数化写法 logger.info("值 {}", obj),避免无效拼接;唯一必须拼接的场景是异常在非最后一个参数位。JDK 17 + Log4j 2.26 建议配合 lambda:logger.debug("值 {}", () -> expensiveCall())。

Q9:同一 Logger 想同时写控制台和文件怎么办? A:Logger 下并列多个 AppenderRef,并把 additivity 设为 false 防止向 Root 重复传播;各 Appender 可配不同 Layout(控制台 Pattern、文件 JsonTemplate)。

Q10:日志文件权限怎么控制? A:File/RollingFile 支持 fileOwner/fileGroup/filePermissions 属性(POSIX),在 Appender 元素上声明即可;也可由运维统一以 umask 或日志目录 ACL 约束。本文实验以 root 运行,文件默认 644。

八、参考链接

  1. Apache Log4j 官方文档:https://logging.apache.org/log4j/2.x/
  2. Maven 使用手册(Getting Started):https://logging.apache.org/log4j/2.x/manual/getting-started.html
  3. log4j-api 2.26.1 下载:https://repo.maven.apache.org/maven2/org/apache/logging/log4j/log4j-api/2.26.1/
  4. log4j-core 2.26.1 下载:https://repo.maven.apache.org/maven2/org/apache/logging/log4j/log4j-core/2.26.1/
  5. Disruptor 4.0.0:https://repo.maven.apache.org/maven2/com/lmax/disruptor/4.0.0/
  6. Log4j ThreadContext 手册:https://logging.apache.org/log4j/2.x/manual/thread-context.html