最近为了避免线上日志量过多,我们团队采用了多种方法去减少日志,其中减少/删除日志堆栈是一个还算不错的方法
在这里总结下减少/消除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>