最近为了避免线上日志量过多,我们团队采用了多种方法去减少日志,其中减少/删除日志堆栈是一个还算不错的方法
在这里总结下减少/消除Exception堆栈深度的三个方法
1.生成Exception时不生成堆栈
异常的层次如下
Throwable
Exception
RuntimeException
当new Exception时都会调用父类的构造方法,而错误堆栈的填充他是存在与Throwable的构造方法中
/**
* Constructs a new throwable with {@code null} as its detail message.
* The cause is not initialized, and may subsequently be initialized by a
* call to {@link #initCause}.
*
* <p>The {@link #fillInStackTrace()} method is called to initialize
* the stack trace data in the newly created throwable.
*/
public Throwable() {
fillInStackTrace();
}
而fillInStackTrace是一个public的方法可以通过继承的方式覆盖掉
public class MyRunntimeException extends RuntimeException{
public Throwable fillfillInStackTrace(){
return this;
}
}
这样就可以完全不生成堆栈信息了可以极大的提升性能,不过对于框架来说那些Exception你无法定制所以不能用如上的方法
2.改写Log4J的Layout的ignoresThrowable方法,当该方法返回的值为false时不会渲染堆栈信息
public class PatternLayoutWithOutStackTrace extends PatternLayout {
@Override
public boolean ignoresThrowable() {
return false;
}
}
3.改变堆栈长度
Log4J在处理LogEvent的时候提供了一个FilterChain(org.apache.log4j.spi.Filter)
那我们就可以在设置appender的时候添加一个我们定制的Filter来减少或者关闭堆栈深度
package learn.log4j;
import org.apache.log4j.spi.Filter;
import org.apache.log4j.spi.LoggingEvent;
public class LogStackTraceFilter extends Filter {
//调整后的堆栈深度,-1表示不调整
private int logLevel = -1;
public void setLogLevel(int logLevel) {
this.logLevel = logLevel;
}
@Override
public int decide(LoggingEvent event) {
Throwable throwable = event.getThrowableInformation().getThrowable();
while (throwable != null) {
//获取堆栈信息
StackTraceElement[] stackTraceElements = throwable.getStackTrace();
//截短堆栈
if (logLevel > -1 && stackTraceElements != null && stackTraceElements.length > logLevel) {
StackTraceElement[] truncateStackTraceElement = new StackTraceElement[logLevel];
for (int currLevel = 0; currLevel < logLevel; currLevel++) {//只需要最上层的堆栈信息就好
truncateStackTraceElement[currLevel] = stackTraceElements[currLevel];
}
throwable.setStackTrace(truncateStackTraceElement);
}
throwable = throwable.getCause() != throwable ? throwable.getCause() : null;
}
return Filter.NEUTRAL;
}
}
在log4j.xml中配置上这个filter即可
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/> </layout> //控制堆栈深度的Filter <filter class="learn.log4j.LogStackTraceFilter"> //堆栈深度设置为10 <param name="logLevel" value="10"/> </filter> </appender>