zoukankan      html  css  js  c++  java
  • 统一记录日志

    统一日志记录

    项目中经常会遇到日志打印,通常的做法是使用Filter统一拦截处理。但如果想打印body里的数据,会出现不能再次读取的问题,servlet的requestbody以及response的body只能被读取一次,一旦流被读取了,就无法再次读取了。

    推荐使用Spring本身提供的Wrapper类来解决此问题,当然也可以自己封装个Wrapper类,继承HttpServletRequestWrapper即可。本文介绍Spring提供的Wrapper的使用。

    caching wrapper

    ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
    ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
    

    spring提供了ContentCachingRequestWrapper以及ContentCachingResponseWrapper两个类,来解决这类问题。 读取完body之后再设置回去。

    wrappedResponse.copyBodyToResponse();
    

    Filter
    完整的filter如下,可参考修改使用:

    
    import com.alibaba.fastjson.JSONObject;
    import org.apache.commons.io.IOUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.slf4j.MDC;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StopWatch;
    import org.springframework.web.filter.OncePerRequestFilter;
    import org.springframework.web.util.ContentCachingRequestWrapper;
    import org.springframework.web.util.ContentCachingResponseWrapper;
    import org.springframework.web.util.WebUtils;
    
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.net.URLDecoder;
    import java.util.Enumeration;
    import java.util.Objects;
    import java.util.UUID;
    
    
    @Component
    public class LogFilter extends OncePerRequestFilter {
        private final Logger logger = LoggerFactory.getLogger(getClass());
    
        public static final String TRACE_ID = "traceId";
        public static final int SLOW_TIME_MILLIS = 5000;
        public static final int LOG_MAX_LENGTH = 1024;
    
        @Override
        protected void doFilterInternal(
                HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {
            String url = null;
            String headers = null;
            String traceId = "";
    
            StopWatch watch = null;
            try {
                url = getCompleteUrl(request);
                // 暂时不打印headers内容
                // headers = getHeaders(request).toString();
                // 设置traceId
                traceId = request.getHeader(TRACE_ID);
                if (StringUtils.isBlank(traceId)) {
                    traceId = UUID.randomUUID().toString();
                }
                MDC.put(TRACE_ID, traceId);
    
                request = new ContentCachingRequestWrapper(request);
                response = new ContentCachingResponseWrapper(response);
    
                watch = new StopWatch();
                watch.start();
    
                logger.info("start request, ip:{} host:{} traceId:{} url:{} header:{} body:{}", getRemortIP(request),
                        request.getRemoteHost(), traceId, url, headers, getRequestBody(request));
                filterChain.doFilter(request, response);
    
            } finally {
                if (watch != null) {
                    watch.stop();
                    if (watch.getTotalTimeMillis() > SLOW_TIME_MILLIS && !url.endsWith(".js")) {
                        logger.info("end slow request, ip:{} host:{} traceId:{} url:{} header:{} cost:{} ms resp:{}", getRemortIP(request),
                                request.getRemoteHost(), traceId, url, headers, watch.getTotalTimeMillis(), getResponseBody(response));
                    } else {
                        logger.info("end request, ip:{} host:{} traceId:{} url:{} header:{} cost:{} ms resp:{}", getRemortIP(request),
                                request.getRemoteHost(), traceId, url, headers, watch.getTotalTimeMillis(), getResponseBody(response));
                    }
                }
                MDC.clear();
                updateResponse(response);
            }
        }
    
        @Override
        public void destroy() {
    
        }
    
    
        private String getRequestBody(HttpServletRequest request) {
            ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
            if (wrapper == null) {
                return "";
            }
            return getBody(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding());
        }
    
        private String getBody(byte[] contentAsByteArray, String characterEncoding) {
            String body = "";
            try {
                body = IOUtils.toString(contentAsByteArray, characterEncoding);
                if (body == null) {
                    return body;
                }
                // 最多打印1024字符
                ///body = body.replaceAll("
    ", "");
                if (body.length() > LOG_MAX_LENGTH) {
                    body = body.substring(0, LOG_MAX_LENGTH) + "...";
                }
            } catch (Exception e) {
                // NOOP
            }
            return body;
        }
    
        /**
         * 获取 response body
         *
         * @param response
         * @return 最长返回1024字符,避免打印过长
         */
        private String getResponseBody(HttpServletResponse response) {
            ContentCachingResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
            if (responseWrapper == null) {
                return "";
            }
            return getBody(responseWrapper.getContentAsByteArray(), "UTF-8");
        }
    
        private void updateResponse(HttpServletResponse response) throws IOException {
            ContentCachingResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
            Objects.requireNonNull(responseWrapper).copyBodyToResponse();
        }
    
        private String getCompleteUrl(HttpServletRequest request) {
            String url = request.getRequestURL().toString();
            String queryString = "";
            if (StringUtils.isNotEmpty(request.getQueryString())) {
                try {
                    queryString = URLDecoder.decode(request.getQueryString(), "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    logger.error("URLDecoder.decode error:" + e.getMessage(), e);
                }
                url = url + "?" + queryString;
            }
            return url;
        }
    
        /**
         * 获取header信息
         *
         * @param request
         * @return headersMap
         */
        private JSONObject getHeaders(HttpServletRequest request) {
            JSONObject map = new JSONObject();
            Enumeration headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {
                String key = (String) headerNames.nextElement();
                String value = request.getHeader(key);
                map.put(key, value);
            }
            return map;
        }
    
        private String getRemortIP(HttpServletRequest request) {
            if (request.getHeader("x-forwarded-for") == null) {
                return request.getRemoteAddr();
            }
            return request.getHeader("x-forwarded-for");
        }
    
    }
    
    
    
  • 相关阅读:
    八大排序算法思想介绍
    关于高并发问题的点滴思考
    一致性Hash算法的原理与实现(分布式映射算法)
    Java线程安全与锁优化
    JAVA体系的线程的实现,线程的调度,状态的转换
    CSS + ul li 横向排列的两种方法
    CSS 有序或者无序列表的前面的标记 list-style-type 属性
    HTML+CSS实现导航栏二级下拉菜单完整代码
    C#中关于DataGridView行和列的背景色-前景色设置
    WinForm------GridControl单元格内容修改外表样式
  • 原文地址:https://www.cnblogs.com/iiot/p/14594213.html
Copyright © 2011-2022 走看看