能否用Log4j2文件追加器捕获InternalError及虚拟机错误?如何调整配置?
问题解决:让Log4j2捕获虚拟机错误并输出到文件
问题分析
你遇到的java.lang.InternalError属于虚拟机错误(VirtualMachineError),这类错误由JVM层面抛出,默认情况下可能直接输出到标准错误流(System.err)而非经过应用的Log4j2框架,导致只有控制台可见,未写入日志文件。
调整Log4j2配置方案
要让这类错误也输出到指定文件,需要从两个维度配置:捕获System.err输出、确保未捕获异常被Log4j2处理。
1. 修改log4j2.xml配置,捕获System.err到文件
以下是完整的配置示例,实现同时将应用日志、System.err输出写入文件和控制台:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <!-- 定义文件追加器,输出到指定日志文件 --> <Appenders> <RollingFile name="FileAppender" fileName="logs/app.log" filePattern="logs/app-%d{yyyy-MM-dd}.log.gz"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> </Policies> </RollingFile> <!-- 控制台追加器,输出System.out内容 --> <Console name="ConsoleOut" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> <!-- 捕获System.err的控制台追加器,路由到文件追加器 --> <Console name="ConsoleErr" target="SYSTEM_ERR"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level [SYSTEM_ERR] %msg%n"/> </Console> </Appenders> <Loggers> <!-- 根日志记录器,输出应用日志到控制台和文件 --> <Root level="info"> <AppenderRef ref="ConsoleOut"/> <AppenderRef ref="FileAppender"/> </Root> <!-- 将System.err的输出转发到文件追加器 --> <Logger name="org.apache.logging.log4j.core.appender.ConsoleAppender" level="error" additivity="false"> <AppenderRef ref="FileAppender"/> </Logger> </Loggers> </Configuration>
2. 手动重定向System.err到Log4j2(可选,用于极端场景)
如果上述配置仍无法捕获JVM直接输出的错误,可以在应用启动的main方法中手动重定向System.err到Log4j2的日志记录器:
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; public class Main { public static void main(String[] args) { Logger errLogger = LogManager.getLogger("SystemErrLogger"); System.setErr(new PrintStream(new ByteArrayOutputStream() { @Override public void flush() throws IOException { String errMsg = this.toString().trim(); if (!errMsg.isEmpty()) { errLogger.error(errMsg); reset(); } } @Override public void write(int b) throws IOException { super.write(b); if (b == '\n') { flush(); } } }, true)); // 应用启动逻辑... } }
关于虚拟机错误能否被Log4j2文件追加器捕获的问题
- 多数情况下,VirtualMachineError(如InternalError、OutOfMemoryError)如果是在应用线程执行过程中抛出,且能被异常处理逻辑(try-catch块或全局未捕获异常处理器)捕获,Log4j2可以将其记录到文件。
- 但如果是JVM内部发生的致命错误(如严重内存不足导致JVM崩溃),此时JVM已无法正常执行应用代码,Log4j2的日志写入流程会失效,这类错误会直接由JVM输出到控制台或生成
hs_err_pid崩溃日志,无法被Log4j2捕获。
内容的提问来源于stack exchange,提问作者Vamsi Krishna DS
相关产品推荐
相关产品推荐

