清除Java堆栈跟踪中的噪音

我的Java堆栈跟踪有很多我不关心的条目,显示通过代理和Springreflection方法的方法调用以及类似的东西。 它可能很难从我的代码中挑选出实际来自堆栈跟踪的部分。 Ruby on Rails包含一个“堆栈跟踪清理器”,您可以在其中指定堆栈跟踪模式列表以从打印的堆栈跟踪中省略 – 对于Java来说,通用的最佳方法是什么?

如果这在任何地方都有效,那将是最好的,包括Eclipse jUnit runner。

eclipse有一个首选项Stack trace过滤模式 (查看java > junit或在首选项中搜索stacktrace )。 您可以忽略包(也包含通配符),类或方法。 适用于直接测试调用(通过Run as junit Test ),而不是像antmaven这样的命令行运行。

intellij-idea允许自定义堆栈跟踪折叠 ,尤其适用于动态语言 。

IntelliJ http://blogs.jetbrains.com/idea/wp-content/uploads/2010/07/screen-shot-2010-07-12-at-100921-pm.png

和分析外部堆栈跟踪工具。

我可以想象一般工具/filter在日志框架(如logback或log4j )级别上工作。 我不认为对此有任何普遍支持,但我认为实施这一点是个好主意。 我会看看,也许这不是那么多工作。

更新:我在日志中实现了过滤不相关的堆栈跟踪线以进行回溯 ,也遵循LBCLASSIC-325 。

我实际上写了一个包含几个实用程序的库( https://github.com/michaelgantman/Mgnt/releases/tag/1.01 )。 其中一个是我广泛使用的通用堆栈跟踪filter,发现它非常有用。 该类称为TextUtils,它具有带有多个重写签名的方法getStacktrace()。 它需要一个Throwable实例,并允许设置相关包的包前缀。 假设您公司的代码始终位于以“com.plain。*”开头的包中。所以您设置了这样的前缀并执行此操作

 logger.info(TextUtils.getStacktrace(e, true, "com.plain.")); 

这将非常巧妙地过滤掉跟踪中所有无用的部分,为您提供非常简洁的堆栈跟踪。 此外,我发现预先设置前缀非常方便,然后只使用方便的方法

 TextUtils.getStacktrace(e); 

它也会这样做。 要预设前缀,只需使用方法

 setRelevantPackage("com.plain."); 

此外,如果您使用Spring环境,您可以将以下段添加到Spring配置中,然后全部设置:

      

该库附带写得很好(我希望)Javadoc,它详细解释了所有内容。 但这里有一个小预告:你会得到一个跟随堆栈跟踪:

 at com.plain.BookService.listBooks() at com.plain.BookService$$FastClassByCGLIB$$e7645040.invoke() at net.sf.cglib.proxy.MethodProxy.invoke() ... at com.plain.LoggingAspect.logging() at sun.reflect.NativeMethodAccessorImpl.invoke0() ... at com.plain.BookService$$EnhancerByCGLIB$$7cb147e4.listBooks() at com.plain.web.BookController.listBooks() 

代替

 at com.plain.BookService.listBooks() at com.plain.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.plain.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.plain.BookService$$EnhancerByCGLIB$$7cb147e4.listBooks() at com.plain.web.BookController.listBooks() 

对于log4j:

 package package1; public class FilteringThrowableRenderer implements ThrowableRenderer { private static final String PACKAGES_SEPARATOR = "\\s*,\\s*"; private final static String TRACE_PREFIX = "\tat "; private static final String FILTERED_WARNING = " [Stacktrace is filtered]"; ThrowableRenderer defaultRenderer = new EnhancedThrowableRenderer(); List skippedLinePrefixes; public FilteringThrowableRenderer() { String skippedPackagesString = "java,org"; // TODO: move it to config String[] skippedPackages = skippedPackagesString.trim().split(PACKAGES_SEPARATOR); skippedLinePrefixes = new ArrayList(skippedPackages.length); for (String packageName : skippedPackages) { skippedLinePrefixes.add(TRACE_PREFIX + packageName); } } @Override public String[] doRender(Throwable throwable) { String[] initialTrace = defaultRenderer.doRender(throwable); if (!skippedLinePrefixes.isEmpty()) { List result = new ArrayList(initialTrace.length); boolean filtered = false; trace: for (String element : initialTrace) { for (String skippedLinePrefix : skippedLinePrefixes) { if (element.startsWith(skippedLinePrefix)) { filtered = true; continue trace; } } result.add(element); } if (filtered && result.size() > 0) { result.set(0, result.get(0) + FILTERED_WARNING); } return result.toArray(new String[result.size()]); } else { return initialTrace; } } } 

使用代码启用它:

 ThrowableRendererSupport loggerRepository = (ThrowableRendererSupport) LogManager.getLoggerRepository(); loggerRepository.setThrowableRenderer(new FilteringThrowableRenderer()); 

或者使用log4j.properties:

 log4j.throwableRenderer=package1.FilteringThrowableRenderer 

不完全是你想要的(并且据我所知,你的问题没有通用的解决方案,至少我从来没有听说过一个着名的工具来清理和从Java堆栈中提取信息)。

无论如何, 2011年7月5日在Faux’Blog上发布的这篇文章描述了早期阶段的Java代理,其目的是丰富(而不是过滤)堆栈跟踪。 它提供了一个带有mavenized项目的git存储库的链接。 也许你可以从这里开始,调整他的代码并推出自己的解决方案(谁知道,甚至可能启动一个开源项目)。

这个插件很不错

 https://marketplace.eclipse.org/content/grep-console 

只是Eclipse控制台的通用grep格式化实用程序,因此没有其他依赖项。 我将所有无关的噪音格式化为灰色文本。