|
项目启动,控制控制台一片空白。打印你写了 log4j.properties,控制也放了 log4j.xml,打印甚至 log4j2.xml 都试了一遍,控制Spring Boot 启动时那句 "Starting Application" 倒是打印出来了,但你自己代码里的控制 logger.info("...") 就是不见踪影。这不是打印灵异事件,是控制依赖冲突在作祟。 Spring Boot 默认用的打印日志实现是 Logback,不是控制 Log4j。你引入 spring-boot-starter-logging 的打印时候,它已经悄悄把 logback-classic 和 log4j-to-slf4j 一起拖进来了。控制注意那个 log4j-to-slf4j,打印它的控制作用是把 Log4j2 的 API 调用桥接到 SLF4J,再由 Logback 输出。如果你只加了 Log4j 的配置文件,但类路径上跑的是 Logback,那你的配置根本没人读。 我见过一个典型场景。有人在 pom.xml 里同时写了 spring-boot-starter-web 和 log4j:log4j:1.2.17。启动时控制台只打印 Spring 自己的日志,业务日志全丢。原因很简单:Spring Boot 的 LoggingSystem 在类路径上先发现了 Logback,就把它当作日志实现。Log4j 1.x 的 Logger 类虽然存在,但它的 Appender 没有初始化,因为 Log4j 的 LogManager 根本没被触发。你调用 Logger.getLogger("foo").info("bar"),它内部检查仓库,发现没有配置,直接静默返回。 那怎么确认?在启动类里加一行 System.out.println(org.slf4j.LoggerFactory.getILoggerFactory().getClass().getName())。如果输出是 ch.qos.logback.classic.LoggerContext,那 Log4j 的配置文件就是废纸。如果输出是 org.apache.logging.log4j.simple.SimpleLoggerContext 或者 org.apache.log4j.spi.LoggerContext,那还有救。 有人会说:我排除了 spring-boot-starter-logging,也加了 spring-boot-starter-log4j2,为什么还是不打印?检查一下 spring-boot-starter-log4j2 的传递依赖。它里面包含 log4j-slf4j-impl,这个才是把 SLF4J 绑定到 Log4j2 的关键。如果你手动排除了 log4j-slf4j-impl,或者版本对不上,SLF4J 会找不到绑定,然后它自己打印一条警告 "Failed to load class org.slf4j.impl.StaticLoggerBinder",之后所有日志调用都变成空操作。控制台不报错,但也不输出,你根本不知道问题在哪。 还有一种隐蔽情况:用了 spring-boot-maven-plugin 打可执行 jar,但 log4j2.xml 放在 src/main/resources 下,打包后却在 BOOT-INF/classes 里。Log4j2 默认会从类路径根目录找配置文件,路径没错。可如果你在 application.properties 里写了 logging.config=classpath:log4j2.xml,而 Spring Boot 的日志系统初始化早于你的配置加载,它可能先用了默认的 Logback 配置,然后 Log4j2 的配置再也没机会生效。顺序问题。 我自己的做法是:先跑 mvn dependency:tree | grep log,看看到底有哪些日志实现。如果出现 logback-classic 和 log4j-slf4j-impl 同时存在,那 SLF4J 会随机选一个,或者选第一个找到的。这时候必须显式排除一个。比如: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> 然后加上 spring-boot-starter-log4j2。再检查 log4j2.xml 里有没有 <Configuration status="WARN">,把 status 改成 TRACE 能看到 Log4j2 内部初始化过程。如果它连配置文件都没找到,会打印 "No log4j2 configuration file found. Using default configuration: logging only errors to the console"。这句话一出来,问题就定位了。 最后说一个容易忽略的点:Spring Boot 2.4 以后,spring-boot-starter-log4j2 默认使用 Log4j2 的异步日志,需要 log4j2.component.properties 或者系统属性 -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector。如果你没配,它还是同步的,但不会导致不打印。真正不打印的原因,九成是类路径上 Logback 和 Log4j 的绑定混乱。清理依赖,只留一个实现,问题就消失了。 |