SLF4J LOGGER如何记录异常栈轨迹?示例测试失败问题求解
解决方案:将SLF4J异常栈轨迹纳入日志检查的方法
问题根因
你当前断言失败的核心原因是:ch.qos.logback.classic.spi.ILoggingEvent 接口的 getFormattedMessage() 方法只会返回日志调用时传入的第一个字符串参数的格式化结果,也就是你示例中的problem here。你传入的异常对象的消息、栈轨迹是独立存储在事件的ThrowableProxy属性中的,不会包含在getFormattedMessage()的返回值里。控制台能看到异常栈是因为控制台默认的Appender配置了打印异常的规则,和日志事件本身的消息字段是分开的。
解决方法
方法1:直接从日志事件中读取异常信息(推荐,无需修改日志配置)
直接读取ILoggingEvent的ThrowableProxy属性做断言,不需要调整日志配置,性能更高:
// 替换原有的断言代码即可 ILoggingEvent errorEvent = listAppender.list.get(1); // 校验日志事件确实携带了异常 Assertions.assertNotNull(errorEvent.getThrowableProxy()); // 校验异常的消息内容 Assertions.assertTrue(errorEvent.getThrowableProxy().getMessage().contains("Oops")); // 如果需要校验完整栈轨迹,可调用getStackTraceElementProxyArray()遍历栈帧
方法2:将异常栈拼入格式化后的日志文本
如果你的业务场景需要把异常栈和日志消息合并为完整的文本内容,可以给ListAppender配置包含异常打印的布局,再读取格式化后的完整日志:
public static void main(String[] args) { final Logger LOGGER = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("TestException"); final ListAppender<ILoggingEvent> listAppender = new ListAppender<>(); // 给ListAppender配置带异常打印的布局 PatternLayout layout = new PatternLayout(); // 布局规则里的%ex就是打印异常栈的占位符 layout.setPattern("%msg%n%ex"); layout.setContext(LOGGER.getLoggerContext()); layout.start(); listAppender.setLayout(layout); listAppender.start(); LOGGER.addAppender(listAppender); NullPointerException testException = new NullPointerException("Oops!"); LOGGER.info("doing stuff"); LOGGER.error("problem here", testException); // 用布局格式化事件,拿到包含异常栈的完整文本 String fullLog = layout.doLayout(listAppender.list.get(1)); Assertions.assertTrue(fullLog.contains("Oops")); }
内容的提问来源于stack exchange,提问作者boardtc
相关产品推荐
相关产品推荐

