perf(log/httptrace-pro): 优化日志过滤器,仅在需要记录请求体、响应体时进行过滤

This commit is contained in:
2024-01-03 21:25:31 +08:00
parent eb290787ce
commit d68d88db21
3 changed files with 58 additions and 13 deletions

View File

@@ -45,11 +45,11 @@ import top.charles7c.continew.starter.log.httptracepro.handler.LogInterceptor;
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class LogAutoConfiguration implements WebMvcConfigurer { public class LogAutoConfiguration implements WebMvcConfigurer {
private final LogProperties properties; private final LogProperties logProperties;
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor(logDao(), properties)); registry.addInterceptor(new LogInterceptor(logDao(), logProperties));
} }
/** /**
@@ -58,7 +58,7 @@ public class LogAutoConfiguration implements WebMvcConfigurer {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public LogFilter logFilter() { public LogFilter logFilter() {
return new LogFilter(); return new LogFilter(logProperties);
} }
/** /**

View File

@@ -27,11 +27,14 @@ import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper; import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper; import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils; import org.springframework.web.util.WebUtils;
import top.charles7c.continew.starter.log.common.enums.Include;
import top.charles7c.continew.starter.log.httptracepro.autoconfigure.LogProperties;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
/** /**
* 日志过滤器 * 日志过滤器
@@ -47,6 +50,8 @@ import java.util.Objects;
@RequiredArgsConstructor @RequiredArgsConstructor
public class LogFilter extends OncePerRequestFilter implements Ordered { public class LogFilter extends OncePerRequestFilter implements Ordered {
private final LogProperties logProperties;
@Override @Override
public int getOrder() { public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 10; return Ordered.LOWEST_PRECEDENCE - 10;
@@ -59,18 +64,28 @@ public class LogFilter extends OncePerRequestFilter implements Ordered {
filterChain.doFilter(request, response); filterChain.doFilter(request, response);
return; return;
} }
// 包装输入、输出流,可重复读取 // 包装输入流,可重复读取
if (!(request instanceof ContentCachingRequestWrapper)) { if (isRequestWrapper(request)) {
request = new ContentCachingRequestWrapper(request); request = new ContentCachingRequestWrapper(request);
} }
if (!(response instanceof ContentCachingResponseWrapper)) { // 包装输出流,可重复读取
boolean isResponseWrapper = isResponseWrapper(response);
if (isResponseWrapper) {
response = new ContentCachingResponseWrapper(response); response = new ContentCachingResponseWrapper(response);
} }
filterChain.doFilter(request, response); filterChain.doFilter(request, response);
// 更新响应(不操作这一步,会导致接口响应空白) // 更新响应(不操作这一步,会导致接口响应空白)
updateResponse(response); if (isResponseWrapper) {
updateResponse(response);
}
} }
/**
* 请求是否有效
*
* @param request 请求对象
* @return truefalse
*/
private boolean isRequestValid(HttpServletRequest request) { private boolean isRequestValid(HttpServletRequest request) {
try { try {
new URI(request.getRequestURL().toString()); new URI(request.getRequestURL().toString());
@@ -80,6 +95,36 @@ public class LogFilter extends OncePerRequestFilter implements Ordered {
} }
} }
/**
* 是否需要包装输入流
*
* @param request 请求对象
* @return truefalse
*/
private boolean isRequestWrapper(HttpServletRequest request) {
Set<Include> includeSet = logProperties.getInclude();
return !(request instanceof ContentCachingRequestWrapper)
&& (includeSet.contains(Include.REQUEST_BODY) || includeSet.contains(Include.REQUEST_PARAM));
}
/**
* 是否需要包装输出流
*
* @param response 响应对象
* @return truefalse
*/
private boolean isResponseWrapper(HttpServletResponse response) {
Set<Include> includeSet = logProperties.getInclude();
return !(response instanceof ContentCachingResponseWrapper)
&& (includeSet.contains(Include.RESPONSE_BODY) || includeSet.contains(Include.RESPONSE_PARAM));
}
/**
* 更新响应
*
* @param response 响应对象
* @throws IOException /
*/
private void updateResponse(HttpServletResponse response) throws IOException { private void updateResponse(HttpServletResponse response) throws IOException {
ContentCachingResponseWrapper responseWrapper = ContentCachingResponseWrapper responseWrapper =
WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class); WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);

View File

@@ -49,8 +49,8 @@ import java.util.Set;
@RequiredArgsConstructor @RequiredArgsConstructor
public class LogInterceptor implements HandlerInterceptor { public class LogInterceptor implements HandlerInterceptor {
private final LogDao dao; private final LogDao logDao;
private final LogProperties properties; private final LogProperties logProperties;
private final TransmittableThreadLocal<LogRecord.Started> timestampTtl = new TransmittableThreadLocal<>(); private final TransmittableThreadLocal<LogRecord.Started> timestampTtl = new TransmittableThreadLocal<>();
@Override @Override
@@ -58,7 +58,7 @@ public class LogInterceptor implements HandlerInterceptor {
@NonNull Object handler) { @NonNull Object handler) {
Clock timestamp = Clock.systemUTC(); Clock timestamp = Clock.systemUTC();
if (this.isRequestRecord(handler, request)) { if (this.isRequestRecord(handler, request)) {
if (Boolean.TRUE.equals(properties.getIsPrint())) { if (Boolean.TRUE.equals(logProperties.getIsPrint())) {
log.info("[{}] {}", request.getMethod(), request.getRequestURI()); log.info("[{}] {}", request.getMethod(), request.getRequestURI());
} }
LogRecord.Started startedLogRecord = LogRecord.start(timestamp, new RecordableServletHttpRequest(request)); LogRecord.Started startedLogRecord = LogRecord.start(timestamp, new RecordableServletHttpRequest(request));
@@ -75,7 +75,7 @@ public class LogInterceptor implements HandlerInterceptor {
return; return;
} }
timestampTtl.remove(); timestampTtl.remove();
Set<Include> includeSet = properties.getInclude(); Set<Include> includeSet = logProperties.getInclude();
try { try {
LogRecord finishedLogRecord = startedLogRecord.finish(new RecordableServletHttpResponse(response, response.getStatus()), includeSet); LogRecord finishedLogRecord = startedLogRecord.finish(new RecordableServletHttpResponse(response, response.getStatus()), includeSet);
HandlerMethod handlerMethod = (HandlerMethod) handler; HandlerMethod handlerMethod = (HandlerMethod) handler;
@@ -87,11 +87,11 @@ public class LogInterceptor implements HandlerInterceptor {
if (includeSet.contains(Include.MODULE)) { if (includeSet.contains(Include.MODULE)) {
this.logModule(finishedLogRecord, handlerMethod); this.logModule(finishedLogRecord, handlerMethod);
} }
if (Boolean.TRUE.equals(properties.getIsPrint())) { if (Boolean.TRUE.equals(logProperties.getIsPrint())) {
LogResponse logResponse = finishedLogRecord.getResponse(); LogResponse logResponse = finishedLogRecord.getResponse();
log.info("[{}] {} {} {}ms", request.getMethod(), request.getRequestURI(), logResponse.getStatus(), finishedLogRecord.getTimeTaken().toMillis()); log.info("[{}] {} {} {}ms", request.getMethod(), request.getRequestURI(), logResponse.getStatus(), finishedLogRecord.getTimeTaken().toMillis());
} }
dao.add(finishedLogRecord); logDao.add(finishedLogRecord);
} catch (Exception ex) { } catch (Exception ex) {
log.error("Logging http log occurred an error: {}.", ex.getMessage(), ex); log.error("Logging http log occurred an error: {}.", ex.getMessage(), ex);
} }