实现思路
- 增加Filter处理请求,生成traceId保存到TreadLocal中(slf4j的MDC)
- 增加返回AOP切面,返回数据之前把traceId写到返回实体里
- 日志logback.xml文件配置增加traceId打印
注意:线程池执行和其他服务请求会丢失traceId,需要再做包装,这里不实现文章来源地址https://www.toymoban.com/news/detail-824242.html
定义过滤器
/**
* @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>
文章来源:https://www.toymoban.com/news/detail-824242.html
到了这里,关于SpringBoot增加全局traceId日志追踪的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!