美文网首页
Filter级别统一异常处理(异常记录日志)

Filter级别统一异常处理(异常记录日志)

作者: 作草分茶 | 来源:发表于2018-12-20 09:54 被阅读0次

    1.介绍

    项目中要做一个转发系统(gateway),转发到的第三方系统可能是web service或者http。采取在filter级别做流向控制,web service的请求由系统内部自己处理,用的apache cxf框架,http的请求由zuul做转发处理。为了记录每一次请求的详情并记录入库,如入参、出参、头信息、请求用户和异常等,在刚进入最外层的filter时创建log对象,并放到ThreadLocal中,在doFilter之后将日志记录入库。

    2.遇到的问题

    在使用中,发现一旦遇到不可预知的异常,线程终止,程序无法走到记录日志入库那一步,导致记录缺失。

    3.解决方案

    参考Spring框架中日志记录的案例,在org.springframework.web.filter.AbstractRequestLoggingFilter中有体现。

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
    
        boolean isFirstRequest = !isAsyncDispatch(request);
        HttpServletRequest requestToUse = request;
    
        if (isIncludePayload() && isFirstRequest && !(request instanceof ContentCachingRequestWrapper)) {
            requestToUse = new ContentCachingRequestWrapper(request, getMaxPayloadLength());
        }
    
        boolean shouldLog = shouldLog(requestToUse);
        if (shouldLog && isFirstRequest) {
            beforeRequest(requestToUse, getBeforeMessage(requestToUse));
        }
        try {
            filterChain.doFilter(requestToUse, response);
        }
        finally {
            if (shouldLog && !isAsyncStarted(requestToUse)) {
                afterRequest(requestToUse, getAfterMessage(requestToUse));
            }
        }
    }
    

    可以看到,此处用try finally进行了巧妙的处理,不管doFilter里面发生了什么,都进行日志处理。
    最终我们仿照这段代码,解决了问题。代码如下:

    Throwable myThrowable = null;
    try {
        filterChain.doFilter(servletRequest, servletResponse);
    } catch (Throwable throwable) {
        // 记录外抛异常
        myThrowable = throwable;
        throw throwable;
    } finally {
        // 记录在doFilter里被程序处理过后的异常,可参考 http://www.runoob.com/servlet/servlet-exception-handling.html
        Throwable throwable = (Throwable) httpRequest.getAttribute("javax.servlet.error.exception");
        if (throwable != null) {
            myThrowable = throwable;
        }
        //日志记录
        LogUtils.postLog(myThrowable);
        //处理ThreadLocal
        ThreadLocals.removeAll();
    }
    

    相关文章

      网友评论

          本文标题:Filter级别统一异常处理(异常记录日志)

          本文链接:https://www.haomeiwen.com/subject/jxvekqtx.html