Cleaning noise out of Java stack traces

2019-01-23 23:53发布

My Java stack traces have a lot of entries that I don't care about, showing method invocation going through proxies and Spring reflection methods and stuff like that. It can make it pretty hard to pick out the part of the stack trace that's actually from my code. Ruby on Rails includes a "stack trace cleaner" where you can specify a list of stack trace patterns to omit from printed stack traces - what's the best way to do something like that, universally, for Java?

It'd be best if this worked everywhere, including in the Eclipse jUnit runner.

6条回答
ゆ 、 Hurt°
2楼-- · 2019-01-24 00:16

has a preference Stack trace filter patterns (look at java > junit or search for stacktrace in the preferences). You can ignore packages (also with wildcards), classes or methods. Does work for direct Test calls (via Run as Test), not for commandline runs like ant or maven.

查看更多
太酷不给撩
3楼-- · 2019-01-24 00:17

I actually wrote a library (https://github.com/michaelgantman/Mgnt/releases/tag/1.01) that contains several utilities. One of them is a general purpose stacktrace filter that I used extensively and found it very useful. The class is called TextUtils and it has method getStacktrace() with several overridden signatures. It takes a Throwable instance and allows to set a package prefix of the packages that are relevant. Let's say your company's code always resides in packages that start with "com.plain.*" So you set such a prefix and do this

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

this will filter out very smartly all the useless parts of the trace leaving you with very concise stacktrace. Also I found it very convinient to pre-set the prefix and then just use the convinience method

TextUtils.getStacktrace(e);

It will do the same. To preset the prefix just use method

setRelevantPackage("com.plain.");

Also if you use Spring environment you can add the following segment to your Spring configuration and then you all set:

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
  <property name="targetClass" value="com.mgnt.utils.TextUtils"/>
  <property name="targetMethod" value="setRelevantPackage"/>
  <property name="arguments" value="com.plain."/>
</bean>

The library comes with well written (I hope) Javadoc that explains everything in detail. But here is a little teaser: you will get a following stacktrace:

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()

instead of

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()
查看更多
地球回转人心会变
4楼-- · 2019-01-24 00:18

Not exactly what you are looking for (and, to the best of my knowledge, there is no universal solution for your problem, at least I've never heard of a famous tool to clean and extract info from Java stacktraces).

Anyway, this post from July, 05, 2011 at Faux' Blog describes a Java Agent in early stages whose purpose is to enrich (and not filter) stack traces. It evens provide a link to a git repository with a mavenized project. Maybe you can go from here, tweak his code and roll your own solution (who knows, maybe even start an open source project).

查看更多
祖国的老花朵
5楼-- · 2019-01-24 00:20

allows customizable stack trace folding, especially useful with dynamic languages.

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

and an Analyzing external stack traces tool.

I can imagine general tool/filter working on logging framework (like or ) level. I don't think there is any general support for that, but I think it is a great idea to implement this. I will have a look, maybe it is not that much work.

UPDATE: I implemented filtering irrelevant stack trace lines in logs for , also follow LBCLASSIC-325.

查看更多
女痞
6楼-- · 2019-01-24 00:26

This plugin's pretty nice

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

Just a generalized grep formatting utility for the Eclipse console, so no additional dependencies. I format all my irrelevant noise to grey text.

查看更多
祖国的老花朵
7楼-- · 2019-01-24 00:30

For 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<String> skippedLinePrefixes;

    public FilteringThrowableRenderer() {
        String skippedPackagesString = "java,org"; // TODO: move it to config
        String[] skippedPackages =
            skippedPackagesString.trim().split(PACKAGES_SEPARATOR);
        skippedLinePrefixes = new ArrayList<String>(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<String> result = new ArrayList<String>(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;
        }
    }
}

to enable it with code:

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

or with log4j.properties:

log4j.throwableRenderer=package1.FilteringThrowableRenderer
查看更多
登录 后发表回答