SpringBoot增加全局traceId日志追踪

实现思路

  1. 增加Filter处理请求,生成traceId保存到TreadLocal中(slf4j的MDC)
  2. 增加返回AOP切面,返回数据之前把traceId写到返回实体里
  3. 日志logback.xml文件配置增加traceId打印

注意:线程池执行和其他服务请求会丢失traceId,需要再做包装,这里不实现

定义过滤器

/**
 * @author lenjor
 * @description requst包装类,构建可重复读取inputStream的request
 * @date 2024-01-24 11:13
 */
public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
    private final byte[] body;

    public RepeatedlyRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = HttpHelper.getBodyString(request).getBytes(StandardCharsets.UTF_8);
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return bais.read();
            }

            @Override
            public int available() throws IOException {
                return body.length;
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        };
    }
}


/**
 * @author lenjor
 * @Description 全局请求增加traceId日志追踪,保存到ThreadLocal的MDC中
 * @Date 2024-01-24 15:29
 */
public class TraceIdFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            String oldTraceId = httpRequest.getHeader("traceId");

            if(!StringUtils.isEmpty(oldTraceId)){
                MDC.put("traceId",oldTraceId);
            }else {
                // 生成唯一的traceId
                MDC.put("traceId", UUID.randomUUID().toString().replace("-", ""));
            }
            if (request instanceof HttpServletRequest && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
                ServletRequest requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request);
                chain.doFilter(requestWrapper, response);
            }else {
                chain.doFilter(request, response);
            }
        } finally {
            // 清除MDC的traceId值,确保在请求结束后不会影响其他请求的日志
            MDC.remove("traceId");
        }
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

/**
 * @author lenjor
 * @Description web请求全局traceId处理
 * @Date 2024-01-24 15:35
 */
@Configuration
public class GlobalWebTraceIdConfig {
    @Bean
    public FilterRegistrationBean<TraceIdFilter> loggingFilter() {
        FilterRegistrationBean<TraceIdFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new TraceIdFilter());
        registrationBean.addUrlPatterns("/*"); // 设置过滤的URL模式
        return registrationBean;
    }
}

返回参数增加traceId

/**
 * @author lenjor
 * @Description 请求返回AOP切面增强,增加traceId返回
 * @Date 2024-01-24 16:06
 */
@ControllerAdvice(basePackages = "com.yingzi.idp.edge.app.v2.interfaces.rest")
public class TraceIdResponseAdvice implements ResponseBodyAdvice<ResultDTO> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return returnType.getMethod().getReturnType().isAssignableFrom(ResultDTO.class);
    }

    @Override
    public ResultDTO beforeBodyWrite(ResultDTO body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (Objects.nonNull(body)) {
            body.setTraceId(MDC.get("traceId"));
        }
        return body;
    }
}

logback.xml增加traceId

        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread]{traceId: %X{traceId}}::: %class{0}.%method\(%line\)
                %msg%n
            </pattern>
        </encoder>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值