spring boot 日志打印、traceId 过滤器 filter

  • Post author:
  • Post category:其他


1.设置增加traceId过滤器


@WebFilter(filterName = "tranceIdFilter",urlPatterns = "/*")
public class TranceIdFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        try {
            // 填充数据(适用logback、log4j 1.x)
            MDC.put("TRACE_ID", UUID.randomUUID().toString().replace("-", ""));
            // 填充数据(适用log4j 2.x)
            chain.doFilter(request, response);
        } finally {
            // 请求结束时清除数据,否则会造成内存泄露问题
            MDC.remove("TRACE_ID");
        }
    }

    @Override
    public void destroy() {}
}

设置打印日志的过滤器:

package com.poloniex.spot.task.filter;

import com.alibaba.fastjson.JSON;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
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.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author: bert.li 李艳强 2022/8/24
 * description:
 */
@WebFilter(filterName = "logFilter",urlPatterns = "/*")
@Slf4j
@Setter
@Getter
public class LogFilter extends OncePerRequestFilter implements Ordered {

    /**
     * 配置要记录请求的路径前缀
     */
    private static final String NEED_TRACE_PATH_PREFIX = "/";
    /**
     * 忽略为multipart/form-data的ContentType的请求
     */
    private static final String IGNORE_CONTENT_TYPE = "multipart/form-data";

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 10;
    }

    @Override
    @SuppressWarnings("NullableProblems")
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (!isRequestValid(request)) {
            filterChain.doFilter(request, response);
            return;
        }
        if (!(request instanceof ContentCachingRequestWrapper)) {
            request = new ContentCachingRequestWrapper(request);
        }
        if (!(response instanceof ContentCachingResponseWrapper)) {
            response = new ContentCachingResponseWrapper(response);
        }
        int status = HttpStatus.INTERNAL_SERVER_ERROR.value();
        long startTime = System.currentTimeMillis();
        String path = request.getRequestURI();
        try {
            filterChain.doFilter(request, response);
            status = response.getStatus();
        } finally {
            if (path.startsWith(NEED_TRACE_PATH_PREFIX) && !Objects.equals(IGNORE_CONTENT_TYPE, request.getContentType())) {
                // 记录 日志
                consoleLog(path, request, startTime, status, response);
            }
            updateResponse(response);
        }
    }

    /**
     * @Description: 打印日志
     * @Param: [path - 请求路径, request - Http请求, startTime - 开始毫秒, status - 响应状态码, response - Http响应]
     * @Author: Magese
     * @Date: 2021/3/5
     */
    private synchronized void consoleLog(String path, HttpServletRequest request, long startTime, int status, HttpServletResponse response) {
        log.info("请求 | 请求路径:[{}] | 请求方法:[{}] | 请求IP:[{}] | 请求参数:{} | 请求Body:{} | 请求Token:[{}] ",
                path,
                request.getMethod(),
                request.getRemoteAddr(),
                JSON.toJSONString(request.getParameterMap()),
                getRequestBody(request),
                request.getHeader("Authorization")
        );
        log.info("返回 | 处理耗时:[{}ms] | 响应状态:[{}] | 响应Body:{} ",
                System.currentTimeMillis() - startTime,
                status,
                getResponseBody(response)
        );
    }

    /**
     * 判断请求是否合法
     * @param request:
     * @return :
     */
    private boolean isRequestValid(HttpServletRequest request) {
        try {
            new URI(request.getRequestURL().toString());
            return true;
        } catch (URISyntaxException ex) {
            return false;
        }
    }

    /**
     * 获取请求Body
     * @param request:
     * @return :
     */
    private String getRequestBody(HttpServletRequest request) {
        String requestBody = "{}";
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            try {
                requestBody = IOUtils.toString(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding());
                requestBody = JSON.parseObject(requestBody).toJSONString();
            } catch (Exception ignored) {}
        }
        return requestBody;
    }

    /**
     * 获取响应Body
     * @param response:
     * @return :
     */
    private String getResponseBody(HttpServletResponse response) {
        String responseBody = "{}";
        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if (wrapper != null) {
            try {
                responseBody = IOUtils.toString(wrapper.getContentAsByteArray(), StandardCharsets.UTF_8.name());
                responseBody = JSON.parseObject(responseBody).toJSONString();
            } catch (IOException ignored) {}
        }
        return responseBody;
    }

    /**
     * 更新响应
     * @param response:
     * @throws IOException:
     */
    private void updateResponse(HttpServletResponse response) throws IOException {
        ContentCachingResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        Objects.requireNonNull(responseWrapper).copyBodyToResponse();
    }

}

注意:引入IOUtils的maven依赖:

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>

将过滤器放入ioc 容器:

@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new TranceIdFilter());
        bean.addUrlPatterns("/*");
        return bean;
    }
}

2.设置日志格式

在 log4j、logback中配置

%X{traceId}

,即可在日志中打印traceId。



版权声明:本文为liyanqiang19原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。