import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.WebUtils;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.UUID;
@Component
@Slf4j
public class RequestLogFilter extends OncePerRequestFilter implements Ordered {
private static final String TID = "TID";
@Value(value = "${method.cost.time.threshold:1000}")
private String methodCostTimeThreshold;
private static final String HEALTH_CHECK_URL = "/api/health-check/status";
@Override
public int getOrder() {
return 20;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
if(!request.getRequestURI().contains(HEALTH_CHECK_URL)) {
long begin = System.currentTimeMillis();
String requestId = UUID.randomUUID().toString().replace("-", "");
MDC.put(TID, requestId);
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
filterChain.doFilter(wrappedRequest, response);
String body = getBody(wrappedRequest);
String username = SecurityContextHolder.getContext().getAuthentication().getName();
long end = System.currentTimeMillis();
long cost = end - begin;
if (StringUtils.isNotEmpty(methodCostTimeThreshold) && cost > Long.parseLong(methodCostTimeThreshold)) {
log.info("Method time cost exceeds threshold[{}],tid: [{}], method:[{}], path:[{}],status:[{}]", cost,
requestId, request.getMethod(), request.getRequestURI(), response.getStatus());
}
log.info("tid: {}, method: {}, path: {}, status: {}, user: {}, userAgent: {}, query: {}, body: {}",
requestId, request.getMethod(), request.getRequestURI(), response.getStatus(),
username, request.getHeader("User-Agent"), request.getQueryString(), body);
}else{
filterChain.doFilter(request, response);
}
} finally {
if(!request.getRequestURI().contains(HEALTH_CHECK_URL)) {
MDC.remove(TID);
}
}
}
private String getBody(ContentCachingRequestWrapper request) {
ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request,
ContentCachingRequestWrapper.class);
if (wrapper != null) {
byte[] buf = wrapper.getContentAsByteArray();
if (buf.length > 0) {
String payload;
try {
payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
} catch (UnsupportedEncodingException ex) {
payload = "[unknown]";
}
return payload;
}
}
return null;
}
}
[Solutions] <RequestLogFilter> 请求日志统一拦截器
最新推荐文章于 2024-02-08 08:30:00 发布