美文网首页
Spring MVC利用过滤器打印日志

Spring MVC利用过滤器打印日志

作者: 艺术类架构师 | 来源:发表于2019-08-06 14:12 被阅读0次

在微服务架构体系中,利用SpringMVC打印单服务日志的实现形式有多种方式,本人了解的如下几种。

1.继承DispatcherServlet.

2.利用拦截器。

3.利用过滤器。

本章直接介绍用过滤器实现简单的打印请求上的输入输出日志,废话不多说了,直接贴干货吧,代码简单易懂!

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.DispatcherType;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
 * 在过滤器中打印输入输出日志
 * @Author
 * @Date 2019-08-06
 */
@Component
@Slf4j
public class LoggingFilter extends OncePerRequestFilter {

    ObjectMapper objectMapper=new ObjectMapper();

    /**
     * 支持打印的MediaType
     */
    private static final Set<MediaType> supportMediaTypes=new HashSet<>();
    {
        supportMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        supportMediaTypes.add(MediaType.APPLICATION_JSON);
        supportMediaTypes.add(MediaType.TEXT_HTML);
        supportMediaTypes.add(MediaType.TEXT_PLAIN);
        supportMediaTypes.add(MediaType.APPLICATION_ATOM_XML);

    }

    final  List<String> resourceRequestsURI = Arrays.asList(
            "/css/", "/js/", "/scss/", "/fonts/",
            ".css", ".js", ".scss", ".eot",
            ".svg", ".ttf", ".woff", ".otf", ".ico", ".png");

    final List<String> swaggerRequestURI = Arrays.asList(
            "/v2/api-docs", "/swagger-resources","swagger-ui");

    @Override
    protected void doFilterInternal( HttpServletRequest httpServletRequest,
                                     HttpServletResponse httpServletResponse,
                                     FilterChain filterChain)  {

       try {

           doLog(httpServletRequest,httpServletResponse,filterChain);
       }
       catch (Exception e){
           log.error("do log filter has a error:{} ", ExceptionUtils.getRootCause(e));
       }
    }

    void doLog(final HttpServletRequest httpServletRequest,
               final HttpServletResponse httpServletResponse,
               final FilterChain filterChain) throws IOException, ServletException {

        ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(httpServletRequest);
        ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(httpServletResponse);

        filterChain.doFilter(requestWrapper, responseWrapper);

        String requestUrl = requestWrapper.getRequestURL().toString();
        String requestId=UUID.randomUUID().toString();
        HttpMethod httpMethod = HttpMethod.valueOf(requestWrapper.getMethod());

        log.info(" request id is: {},http method is:{}",requestId,httpMethod.name());
        log.info("request id is: {},requestUrl  is:{}",requestId, requestUrl);

        Enumeration<String> parameterEnum=requestWrapper.getParameterNames();
        if(!ObjectUtils.isEmpty(parameterEnum)) {
            log.info("request id is: {},request param   is:{}",requestId,getRequestParamJSON(requestWrapper));

        }
        log.info("request id is: {},request header  is:{}", requestId,getRequestHeader(requestWrapper));


        if(HttpMethod.valueOf(httpServletRequest.getMethod())!=HttpMethod.GET) {
            if(supportMediaTypes.contains(MediaType.valueOf(httpServletRequest.getContentType()))) {
                log.info("request id is: {},request body  is:\n{}",requestId, new String(requestWrapper.getContentAsByteArray()));
            }
        }
        HttpStatus responseStatus = HttpStatus.valueOf(responseWrapper.getStatusCode());
        log.info("request id is: {},response status is:{}",requestId ,responseStatus.value());
        String responseBody = IOUtils.toString(responseWrapper.getContentInputStream(), UTF_8);


        if(httpServletRequest.isAsyncSupported()){
            log.info("request id is: {}, response payLoad is:\n{}",requestId, responseBody);
        }
        else if(!isAsyncStarted(httpServletRequest)&&httpServletRequest.getDispatcherType()!= DispatcherType.ASYNC) {
            log.info("request id is: {},response body is:{}",requestId ,objectMapper.readTree(responseBody));
        }

        else {
            log.info("request id is: {}, cause by request is async:response body is:{}", requestId,"empty");

        }
        responseWrapper.copyBodyToResponse();
    }

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request)  {

        String requestUrl=request.getRequestURL().toString();
        return  isResourceUrl(requestUrl)||isSwaggerResource(requestUrl);
    }

    /**
     * 请求参数列表
     * @param requestWrapper
     * @return
     */
    private JSONObject getRequestParamJSON(ContentCachingRequestWrapper requestWrapper){
        Enumeration<String> parameterEnum=requestWrapper.getParameterNames();
        JSONObject paramJsonObject=new JSONObject();
        if(!ObjectUtils.isEmpty(parameterEnum)) {
            while (parameterEnum.hasMoreElements()) {
                String name= parameterEnum.nextElement();
                String []value=requestWrapper.getParameterValues(name);
                paramJsonObject.put(name,value);

            }
        }
        return  paramJsonObject;
    }

    /**
     *
     * @param requestWrapper
     * @return 请求头参数列表
     */
    private JSONObject getRequestHeader(ContentCachingRequestWrapper requestWrapper){

        Enumeration headerNames = requestWrapper.getHeaderNames();
        JSONObject headerJsonObject=new JSONObject();
        while (headerNames.hasMoreElements()) {
            String headerName = (String) headerNames.nextElement();
            headerJsonObject.put(headerName,requestWrapper.getHeader(headerName));
        }
        return  headerJsonObject;
    }

    private boolean isResourceUrl(String url) {
        return resourceRequestsURI.stream().anyMatch(e->url.contains(e));
    }

    private boolean isSwaggerResource(String url) {
        return swaggerRequestURI.stream().anyMatch(e->url.contains(e));

    }
}

附带继承DispatchServlet实现日志打印

package com.application.config;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.BaseJsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

public class CustLoggingDispatcherServlet extends DispatcherServlet {

    private static final org.slf4j.Logger logger = LoggerFactory.getLogger("logging");

    private static final ObjectMapper mapper = new ObjectMapper();

    @Override
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
        //创建一个 json 对象,用来存放 http 日志信息
        ObjectNode rootNode = mapper.createObjectNode();
        rootNode.put("uri", requestWrapper.getRequestURI());
        rootNode.put("clientIp", requestWrapper.getRemoteAddr());
        rootNode.set("requestHeaders", mapper.valueToTree(getRequestHeaders(requestWrapper)));
        String method = requestWrapper.getMethod();
        rootNode.put("method", method);
        try {
            super.doDispatch(requestWrapper, responseWrapper);
        } finally {
            if(method.equals("GET")) {
                rootNode.set("request", mapper.valueToTree(requestWrapper.getParameterMap()));
            }
            else {
                JsonNode newNode = mapper.readTree(requestWrapper.getContentAsByteArray());
                rootNode.set("request", newNode);
            }

            if(response.getContentType().equals(MediaType.APPLICATION_JSON.getType())
                    &&response.getContentType().equals( MediaType.APPLICATION_JSON_UTF8.getType())) {
                JsonNode newNode = mapper.readTree(responseWrapper.getContentInputStream());
                rootNode.set("response", newNode);
            }
            else{
                JsonNode newNode = JsonNodeFactory.instance.textNode(new String(responseWrapper.getContentAsByteArray()));
                rootNode.set("response", newNode);

            }

            responseWrapper.copyBodyToResponse();

            rootNode.set("responseHeaders", mapper.valueToTree(getResponsetHeaders(responseWrapper)));
            logger.info(rootNode.toString());
        }
    }

    private Map<String, Object> getRequestHeaders(HttpServletRequest request) {
        Map<String, Object> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            headers.put(headerName, request.getHeader(headerName));
        }
        return headers;

    }

    private Map<String, Object> getResponsetHeaders(ContentCachingResponseWrapper response) {
        Map<String, Object> headers = new HashMap<>();
        Collection<String> headerNames = response.getHeaderNames();
        for (String headerName : headerNames) {
            headers.put(headerName, response.getHeader(headerName));
        }
        return headers;
    }
}

@Bean
    public ServletRegistrationBean dispatcherRegistration() {
        return new ServletRegistrationBean(dispatcherServlet());
    }
    @Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    public DispatcherServlet dispatcherServlet() {
        return new CustLoggingDispatcherServlet();
    }

相关文章

网友评论

      本文标题:Spring MVC利用过滤器打印日志

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