• springboot filter and interceptor实战之mdc日志打印


    1.1  mdc日志打印全局控制

    1.1.1    logback配置

    <property name="log.pattern" value="%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}%level [%thread] [%logger{50}:%line] [uuid:%X{operation_id}] %msg%n"></property>

    1.1.2    filter配置

     1 @WebFilter(filterName="logFilter", urlPatterns="/*")
     2 
     3 public class LogFilter implements Filter {
     4 
     5     private static final Logger log = LoggerFactory.getLogger(LogInterceptor.class);
     6 
     7    
     8 
     9     @Override
    10 
    11     public void init(FilterConfig filterConfig) throws ServletException {
    12 
    13         log.info("---------log filter init");
    14 
    15     }
    16 
    17  
    18 
    19     @Override
    20 
    21     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    22 
    23             throws IOException, ServletException {
    24 
    25         log.info("log filter doFilter");
    26 
    27         ServletRequest requestWrapper = null;
    28 
    29         requestWrapper = new MyRequestWrapper((HttpServletRequest) request);
    30 
    31         chain.doFilter(requestWrapper, response);
    32 
    33     }
    34 
    35  
    36 
    37     @Override
    38 
    39     public void destroy() {
    40 
    41         log.info("-------------log filter destroy");
    42 
    43        
    44 
    45     }
    46 
    47 }

    同时需要在启动类加上扫描配置

     1 @SpringBootApplication()
     2 
     3 @ServletComponentScan       //扫描过滤器
     4 
     5 public class LogApplication {
     6 
     7  
     8 
     9    public static void main(String[] args) {
    10 
    11        Tools.setMdc(Tools.getUuid());
    12 
    13       SpringApplication.run(LogApplication.class, args);
    14 
    15    }
    16 
    17 }

    1.1.3    自定义httpServletRequest

     1 public class MyRequestWrapper extends HttpServletRequestWrapper {
     2 
     3     private String body;
     4     private String requestMethod;
     5     
     6     public MyRequestWrapper(HttpServletRequest request) throws IOException {
     7         super(request);
     8         StringBuilder sb = new StringBuilder();
     9         String line = null;
    10         BufferedReader reader = request.getReader();
    11         requestMethod = request.getMethod();
    12         
    13         while((line = reader.readLine()) != null) {
    14             sb.append(line);
    15         }
    16         body = sb.toString();
    17     }
    18     private boolean isPostOrPut() {
    19         return "POST".equalsIgnoreCase(requestMethod) || "PUT".equalsIgnoreCase(requestMethod);
    20     }
    21     @Override
    22     public String getQueryString() {
    23         if(isPostOrPut()) {
    24             return body;
    25         } else {
    26             return super.getQueryString();
    27         }
    28     }
    29     @Override
    30     public ServletInputStream getInputStream() throws IOException {
    31         ByteArrayInputStream bais = new ByteArrayInputStream(body.getBytes(CommonVar.DEFAULT_CHARSET));
    32         return new ServletInputStream() {
    33             
    34             @Override
    35             public int read() throws IOException {
    36                 return bais.read();
    37             }
    38 
    39             @Override
    40             public boolean isFinished() {
    41                 return bais.available()==0;
    42             }
    43 
    44             @Override
    45             public boolean isReady() {
    46                 return true;
    47             }
    48 
    49             @Override
    50             public void setReadListener(ReadListener listener) {
    51                 
    52             }
    53         };
    54     }
    55 }

    1.1.4    interceptor配置

     1 public class LogInterceptor implements HandlerInterceptor{
     2     private static final Logger log = LoggerFactory.getLogger(LogInterceptor.class);
     3     
     4     private static final String REQUEST_START_TIME = "request_start_time";
     5     
     6     @Override
     7     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
     8             throws Exception {
     9         setMdc(request);
    10         logRequestMsg(request);
    11         request.setAttribute(REQUEST_START_TIME, System.currentTimeMillis());
    12         System.out.println("preHandle");
    13         return true;
    14     }
    15 
    16     @Override
    17     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    18             ModelAndView modelAndView) throws Exception {
    19         HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    20         System.out.println("postHandle");
    21     }
    22 
    23     @Override
    24     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    25             throws Exception {
    26         logRequestEnd(request);
    27         Tools.removeMdc();
    28         System.out.println("afterCompletion");
    29     }
    30     private void setMdc(HttpServletRequest request) {
    31         MDC.put("operation_id", Tools.getUuid());
    32     }
    33     /**
    34      * log request url and request cost time
    35      * @param request
    36      */
    37     private void logRequestEnd(HttpServletRequest request) {
    38         long startTime = (long) request.getAttribute(REQUEST_START_TIME);
    39         long endTime = System.currentTimeMillis();
    40         long interval = endTime - startTime;
    41         log.debug("request_end: {}, cost time:{}ms",request.getRequestURL(), interval);
    42     }
    43     /**
    44      * log request url and param
    45      * @param request 
    46      * @throws IOException
    47      */
    48     private void logRequestMsg(HttpServletRequest request) throws IOException {
    49         String url = request.getRequestURL().toString();
    50         String method = request.getMethod();
    51         String query = request.getQueryString();
    52         log.debug("request_receive: url:{},method:{},query:{}", url, method, query);
    53     }
    54 }

    新建config类将interceptor注册到spring

     1 @Configuration
     2 public class LogWebAppConfig implements WebMvcConfigurer  {
     3 
     4     @Override
     5     public void addInterceptors(InterceptorRegistry registry) {
     6         registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**");
     7         WebMvcConfigurer.super.addInterceptors(registry);
     8     }
     9     
    10 }

    1.1.5    总体说明

    1.1.5.1   功能说明

    打印请求url,请求类型,请求参数

    打印所有的请求耗时统计

    使用logback的MDC机制打印日志,不了解的自行百度

    1.1.5.2   问题(功能1)

    post,put请求的参数在流里面,只能读取一次,如果在拦截器中读取了流,流就空了,controller层读取会报错。报错信息:

    getReader() has already been called for this request preHandle

    1.1.5.3 解决思想(功能1)

    自定义一个httpServletRequest,提供post参数读取的方法(读完流之后将数据重新写回流中),然后重写getQueryString()方法。这个方法是get等请求获取参数的方式,在这里同样提供post请求的参数,减轻调用者的负担

    使用过滤器过滤所有的请求,替换httpServletRequest为自定义的request,传递给下一条链

    由于过滤器已经替换httpServletRequest,那么这里拿到的就是自定义的httpServletRequest,所以可以不用区分请求类型,直接调用getQueryString() 获取请求参数

    1.1.5.4             其它功能实现

    打印所有的请求耗时统计

      实现方式是在拦截器中为request增加一个字段(本文是request_start_time),记录当前时间,在方法调用完成后从request中拿到这个字段(起始时间),根据当前时间算出调用时间间隔。

    使用logback打印MDC日志

          需要在logback中配置这么一个字段(本文是operation_id),然后在拦截器的入口为这个字段设置一个uuid即可。作用是每个请求对应的日志都有这个uuid。mdc实现原理是threadLocal,所以对于线程池需要额外处理方式。

    1.1.6    结果

    2018-12-08T11:46:23.916+08:00 INFO [localhost-startStop-1] [com.hikvision.log.common.filter.LogInterceptor:23] [uuid:] ---------log filter init

    2018-12-08T11:46:33.307+08:00 INFO [http-nio-8080-exec-3] [com.hikvision.log.common.filter.LogInterceptor:29] [uuid:] log filter doFilter

    2018-12-08T11:46:33.307+08:00 INFO [http-nio-8080-exec-2] [com.hikvision.log.common.filter.LogInterceptor:29] [uuid:] log filter doFilter

    2018-12-08T11:46:33.307+08:00 INFO [http-nio-8080-exec-1] [com.hikvision.log.common.filter.LogInterceptor:29] [uuid:] log filter doFilter

    2018-12-08T11:46:33.326+08:00 DEBUG [http-nio-8080-exec-1] [com.hikvision.log.common.filter.LogInterceptor:67] [uuid:0002] request_receive: url:http://127.0.0.1:8080/settings,method:GET,query:null

    preHandle

    2018-12-08T11:46:33.326+08:00 DEBUG [http-nio-8080-exec-2] [com.hikvision.log.common.filter.LogInterceptor:67] [uuid:0003] request_receive: url:http://127.0.0.1:8080/meta,method:GET,query:null

    preHandle

    2018-12-08T11:46:33.328+08:00 DEBUG [http-nio-8080-exec-3] [com.hikvision.log.common.filter.LogInterceptor:67] [uuid:0004] request_receive: url:http://127.0.0.1:8080/session,method:GET,query:null

    preHandle

    2018-12-08T11:46:33.368+08:00 INFO [http-nio-8080-exec-2] [com.hikvision.log.web.restful.CheckDiskController:45] [uuid:0003] Get availableSpace is:173138524

    2018-12-08T11:46:33.369+08:00 INFO [http-nio-8080-exec-2] [com.hikvision.log.web.restful.CheckDiskController:49] [uuid:0003] Get omcVersion is:

    postHandle

    2018-12-08T11:46:33.453+08:00 DEBUG [http-nio-8080-exec-3] [com.hikvision.log.common.filter.LogInterceptor:56] [uuid:0004] request_end: http://127.0.0.1:8080/session, cost time:124ms

    afterCompletion

    postHandle

    2018-12-08T11:46:33.455+08:00 DEBUG [http-nio-8080-exec-2] [com.hikvision.log.common.filter.LogInterceptor:56] [uuid:0003] request_end: http://127.0.0.1:8080/meta, cost time:129ms

    afterCompletion

    postHandle

    2018-12-08T11:46:33.473+08:00 DEBUG [http-nio-8080-exec-1] [com.hikvision.log.common.filter.LogInterceptor:56] [uuid:0002] request_end: http://127.0.0.1:8080/settings, cost time:147ms

    afterCompletion

  • 相关阅读:
    bzoj 1025: [SCOI2009]游戏【数学+dp】
    bzoj 1195: [HNOI2006]最短母串【状压dp】
    洛谷 P1083 借教室【二分+差分/线段树】
    bzoj 2151: 种树【贪心+堆】
    bzoj 1055: [HAOI2008]玩具取名【区间dp】
    bzoj 2152: 聪聪可可【点分治】
    bzoj 4552: [Tjoi2016&Heoi2016]排序【二分+线段树】
    bzoj 1103: [POI2007]大都市meg【dfs序+树状数组】
    bzoj 3751: [NOIP2014]解方程【数学】
    bzoj 3612: [Heoi2014]平衡【整数划分dp】
  • 原文地址:https://www.cnblogs.com/gc65/p/10087166.html
Copyright © 2020-2023  润新知