Cleaning noise out of Java stack traces

后端 未结 6 1498
感情败类
感情败类 2020-12-15 17:15

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 ca

相关标签:
6条回答
  • 2020-12-15 17:38

    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
    
    0 讨论(0)
  • 2020-12-15 17:44

    eclipse 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 junit Test), not for commandline runs like ant or maven.

    0 讨论(0)
  • 2020-12-15 17:53

    I actually wrote an open source library MgntUtils (available at Github and maven central) that contains several utilities. Here is a link to an article about the library: MgntUtils Open Source Java library. One of the utilities 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()
    
    0 讨论(0)
  • 2020-12-15 17:54

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


    (source: jetbrains.com)

    and an Analyzing external stack traces tool.

    I can imagine general tool/filter working on logging framework (like logback or log4j) 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 logback, also follow LBCLASSIC-325.

    0 讨论(0)
  • 2020-12-15 17:54

    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.

    0 讨论(0)
  • 2020-12-15 17:54

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

    0 讨论(0)
提交回复
热议问题