Java应用基于SLF4J+Logback实现未捕获异常堆栈日志采集方案咨询
解决方案
首先修正你当前logback.xml的配置错误:当前配置定义了两个<root>节点,logback会以最后一个root配置为准,前面配置的ROLLING_FILE文件输出未被加入最终的root引用中,会导致文件日志不生效,先合并root配置:
<!-- 删掉之前两个分开的root节点,合并为一个,同时输出到文件和控制台 --> <root level="INFO"> <appender-ref ref="ROLLING_FILE"/> <appender-ref ref="STDOUT"/> </root>
方案1:全局线程未捕获异常处理器
JVM提供了Thread.UncaughtExceptionHandler接口,可以捕获所有线程未被try-catch处理的异常,包括堆内存溢出这类Error级别的错误,不需要对业务代码做侵入修改。
实现步骤:
- 自定义异常处理器实现类,用SLF4J打印完整异常栈
import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class GlobalUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { private static final Logger log = LoggerFactory.getLogger(GlobalUncaughtExceptionHandler.class); @Override public void uncaughtException(Thread t, Throwable e) { log.error("线程[{}]发生未捕获异常", t.getName(), e); } }
- 应用启动时设置为默认全局处理器,在启动类main方法最开头添加:
Thread.setDefaultUncaughtExceptionHandler(new GlobalUncaughtExceptionHandler());
- 针对自定义线程池额外配置:如果项目中使用了自定义线程池,需要给线程池的线程工厂也绑定该处理器,避免线程池内的异常漏处理:
ThreadFactory factory = new ThreadFactoryBuilder() .setNameFormat("custom-pool-%d") .setUncaughtExceptionHandler(new GlobalUncaughtExceptionHandler()) .build(); ExecutorService executor = new ThreadPoolExecutor(核心线程数, 最大线程数, 存活时间, 时间单位, 阻塞队列, factory);
方案2:JVM参数兜底捕获严重错误
当发生OOM这类严重错误时,可能日志系统已经无法正常工作,可通过JVM自带参数做兜底:
- 堆内存溢出时自动dump堆快照,方便后续排查根因:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./logs/heap_dump.hprof
- OOM发生时触发自定义指令记录日志:
-XX:OnOutOfMemoryError="echo 'OOM occurred at $(date)' >> ./logs/oom.log"
方案3:Spring/SpringBoot Web场景补充
如果是Web应用,可以新增Spring全局异常处理器,捕获Controller层未处理的业务异常:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; @ControllerAdvice public class GlobalExceptionAdvice { private static final Logger log = LoggerFactory.getLogger(GlobalExceptionAdvice.class); @ExceptionHandler(value = Exception.class) @ResponseBody public Object handleException(Exception e) { log.error("请求发生未捕获异常", e); // 这里可以自定义返回给前端的异常响应结构 return "系统异常"; } }
内容的提问来源于stack exchange,提问作者Ethan Solomon
相关产品推荐
相关产品推荐

