减少日志的错误堆栈

最近为了避免线上日志量过多,我们团队采用了多种方法去减少日志,其中减少/删除日志堆栈是一个还算不错的方法

在这里总结下减少/消除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>
 

猜你喜欢

转载自zys0523.iteye.com/blog/1724312