但是有一件事一直困扰着我一段时间。 臭名昭著的“ 来自地狱的堆栈跟踪 ”症状–堆栈跟踪包含数百种不相关的,隐秘的,通常是自动生成的方法。 AOP框架和过度设计的库往往会产生疯狂的长执行跟踪。 让我展示一个真实的例子。 在一个示例应用程序中,我正在使用以下技术堆栈:
颜色很重要。 根据框架/层的颜色,我绘制了一个示例堆栈跟踪,该堆栈跟踪是由于尝试从数据库中获取数据时在某处深处抛出异常而引起的:
不再那么愉快,你不觉得吗? 在第一张图中,将Spring放在应用程序和Hibernate之间是一个极大的简化。 Spring框架是一个胶合代码,用于连接并拦截周围层的业务逻辑。 这就是为什么应用程序代码被数十行技术调用分散和交织的原因(请参见绿线)。 我在应用程序中投入了尽可能多的内容(Spring AOP,方法级别的@Secured批注,自定义方面和拦截器等)来强调该问题-但这不是特定于Spring的。 EJB服务器在EJB调用之间生成同样可怕的堆栈跟踪(…从地狱)。 我应该在乎吗? 想想看,当您从BookController.listBooks()
无辜地调用BookService.listBooks()
,您希望看到此消息吗?
at com.blogspot.nurkiewicz.BookService.listBooks()
at com.blogspot.nurkiewicz.BookService$$FastClassByCGLIB$$e7645040.invoke()
at net.sf.cglib.proxy.MethodProxy.invoke()
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed()
at com.blogspot.nurkiewicz.LoggingAspect.logging()
at sun.reflect.NativeMethodAccessorImpl.invoke0()
at sun.reflect.NativeMethodAccessorImpl.invoke()
at sun.reflect.DelegatingMethodAccessorImpl.invoke()
at java.lang.reflect.Method.invoke()
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs()
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod()
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.aop.interceptor.AbstractTraceInterceptor.invoke()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke()
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept()
at com.blogspot.nurkiewicz.BookService$$EnhancerByCGLIB$$7cb147e4.listBooks()
at com.blogspot.nurkiewicz.web.BookController.listBooks()
您甚至注意到它们之间存在自定义方面吗? 事实就是如此,如今堆栈跟踪中杂乱无章,几乎不可能遵循实际的业务逻辑。 我们拥有的最好的故障排除工具之一是在99%的情况下都不需要与框架相关的无关内容。
工具和IDE在减少噪声方面做得很好。 Eclipse具有用于Junit的堆栈跟踪过滤器模式 , IntelliJ IDEA支持控制台折叠自定义 。 另请参阅: 从Java堆栈跟踪中清除噪音 ,这启发了我写这篇文章。 那么,为什么在Logback等日志记录框架中根本没有这种可能性呢?
我在Logback中实现了一个非常简单的增强。 基本上,您可以定义一组应该从堆栈跟踪中排除的堆栈跟踪框架模式。 通常,您将使用不希望看到的包或类名。 这是启用了新功能的示例logback.xml
摘录:
<root level="ALL"><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{HH:mm:ss.SSS} | %-5level | %thread | %logger{1} | %m%n%rEx{full,java.lang.reflect.Method,org.apache.catalina,org.springframework.aop,org.springframework.security,org.springframework.transaction,org.springframework.web,sun.reflect,net.sf.cglib,ByCGLIB}</pattern></encoder></appender>
</root>
在过滤几乎整个Spring框架+ Java反射和CGLIB类时,我有点极端。 但这只是给您一种印象,您可以得到多少。 将我的增强功能应用到Logback后,出现了非常相同的错误:
提醒一下,绿色是我们的应用程序。 最终在一个地方,最终您可以真正看到发生错误时代码在做什么:
at com.blogspot.nurkiewicz.DefaultBookHelper.findBooks()
at com.blogspot.nurkiewicz.BookService.listBooks()
at com.blogspot.nurkiewicz.LoggingAspect.logging()
at com.blogspot.nurkiewicz.web.BookController.listBooks()
更简单? 如果您喜欢此功能,我打开了一张票LBCLASSIC-325 : 筛选出选定的堆栈跟踪框架 。 投票讨论。 这只是一个概念证明,但是如果您想看一下实现(欢迎改进!),可以在我的Logback 分支下找到(大约20行代码)。
参考:从JCG合作伙伴的 日志中过滤无关的堆栈跟踪行 Java和社区博客中的Tomasz Nurkiewicz。
翻译自: https://www.javacodegeeks.com/2012/03/filter-irrelevant-stack-trace-lines-in.html