文章目录
- 实现思路
- 定义过滤器
- 返回参数增加traceId
- logback.xml增加traceId
实现思路
- 增加Filter处理请求,生成traceId保存到TreadLocal中(slf4j的MDC)
- 增加返回AOP切面,返回数据之前把traceId写到返回实体里
- 日志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);}@Overridepublic BufferedReader getReader() throws IOException {return new BufferedReader(new InputStreamReader(getInputStream()));}@Overridepublic ServletInputStream getInputStream() throws IOException {final ByteArrayInputStream bais = new ByteArrayInputStream(body);return new ServletInputStream() {@Overridepublic int read() throws IOException {return bais.read();}@Overridepublic int available() throws IOException {return body.length;}@Overridepublic boolean isFinished() {return false;}@Overridepublic boolean isReady() {return false;}@Overridepublic void setReadListener(ReadListener readListener) {}};}
}/*** @author lenjor* @Description 全局请求增加traceId日志追踪,保存到ThreadLocal的MDC中* @Date 2024-01-24 15:29*/
public class TraceIdFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {Filter.super.init(filterConfig);}@Overridepublic 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 {// 生成唯一的traceIdMDC.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");}}@Overridepublic void destroy() {Filter.super.destroy();}
}/*** @author lenjor* @Description web请求全局traceId处理* @Date 2024-01-24 15:35*/
@Configuration
public class GlobalWebTraceIdConfig {@Beanpublic 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> {@Overridepublic boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {return returnType.getMethod().getReturnType().isAssignableFrom(ResultDTO.class);}@Overridepublic 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>