基于条件截断日志中异常的堆栈跟踪

5
我正在使用slf4j来记录自定义异常及其堆栈跟踪信息,既可以在控制台上显示,也可以保存在一个自定义文件中。有时我会遇到需要截断某些非关键异常的堆栈跟踪信息的情况。
按照这份文档的说明,在我的logback.xml文件中添加了以下配置:
<evaluator name="DISPLAY_EX_EVAL">
    <expression>throwable != null &amp;&amp; throwable instanceof com.abc.NonCriticalException</expression>
    </evaluator>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%-30(%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread]) %-5level
                %logger{150} -%msg%n%ex{full, DISPLAY_EX_EVAL}
            </pattern>
        </encoder>
    </appender>

但是,上述配置在记录配置的异常时删除了所有堆栈跟踪。是否有一种方法可以记录匹配异常的截断堆栈跟踪(1或2行)?


你好 @Abhishek。这个问题还存在吗?让我看看我是否理解了你的问题:在控制台上,你想要截断堆栈跟踪消息,但仍然希望它们完整记录到文件中。是这样吗? - Gabriel Robaina
请看一下我关于日志记录的另一个答案。https://dev59.com/rbTma4cB1Zd3GeqP_sTY 或许对你有所帮助。不过,我并没有真正理解你的问题... - Gabriel Robaina
2个回答

3

有一个由我编写的开源库,提供智能堆栈跟踪过滤。我在自己的项目中使用它,效果很好。这是关于该库的文章:Open-Source Java Library With Stack Trace Filtering, Silent String Parsing, and Version Comparison。特别是查找段落“Stack Trace Noise Filter”。基本上,它根据您设置的感兴趣的包前缀来过滤堆栈跟踪。您可以在Maven artifactGithub(包括源代码和Javadoc)中找到该库。这里是Javadoc。这里有一个例子。假设您的代码位于包 "com.plain.*"。因此,如果将前缀设置为 "com.plain.",则原始堆栈跟踪将被过滤:

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

将会被替换为:

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

这个工具可以很好地处理整个堆栈跟踪,包括“caused by”和“suppressed”部分,同时可以在运行时进行筛选(从异常本身)或从包含原始堆栈跟踪的字符串中进行筛选。


0

但是你为什么要截断堆栈跟踪呢?为什么不记录完整的堆栈跟踪呢?毕竟,这是重要且有用的信息。对吧?

我猜你在想你必须记录所有异常的堆栈跟踪。那是错误的。你应该只记录表明被调用代码中存在错误(意外异常)的异常的堆栈跟踪。当然,你的程序记录这些堆栈跟踪应该很少见,当它确实发生时,你会希望有完整的堆栈跟踪来帮助你调试问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接