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 版权协议,转载请附上原文出处链接和本声明。