mirror of
				https://github.com/continew-org/continew-starter.git
				synced 2025-11-04 21:04:26 +08:00 
			
		
		
		
	refactor(log): 优化访问日志相关配置属性名称
This commit is contained in:
		@@ -23,12 +23,6 @@
 | 
			
		||||
            <artifactId>spring-boot-configuration-processor</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <!-- servlet包 -->
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>jakarta.servlet</groupId>
 | 
			
		||||
            <artifactId>jakarta.servlet-api</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <!-- Hibernate Validator -->
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.hibernate.validator</groupId>
 | 
			
		||||
@@ -65,5 +59,12 @@
 | 
			
		||||
            <groupId>cn.hutool</groupId>
 | 
			
		||||
            <artifactId>hutool-http</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <!-- Jakarta(原 Javax Servlet) -->
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>jakarta.servlet</groupId>
 | 
			
		||||
            <artifactId>jakarta.servlet-api</artifactId>
 | 
			
		||||
            <optional>true</optional>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
</project>
 | 
			
		||||
@@ -33,8 +33,8 @@ import java.nio.charset.StandardCharsets;
 | 
			
		||||
 * 支持文件流直接透传,非文件流可重复读取
 | 
			
		||||
 *
 | 
			
		||||
 * @author echo
 | 
			
		||||
 * @since 2025/03/25 11:11
 | 
			
		||||
 **/
 | 
			
		||||
 * @since 2.10.0
 | 
			
		||||
 */
 | 
			
		||||
public class RepeatReadRequestWrapper extends HttpServletRequestWrapper {
 | 
			
		||||
 | 
			
		||||
    private byte[] cachedBody;
 | 
			
		||||
@@ -50,13 +50,6 @@ public class RepeatReadRequestWrapper extends HttpServletRequestWrapper {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 检查是否为文件上传请求
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isMultipartContent(HttpServletRequest request) {
 | 
			
		||||
        return request.getContentType() != null && request.getContentType().toLowerCase().startsWith("multipart/");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ServletInputStream getInputStream() throws IOException {
 | 
			
		||||
        // 如果是文件上传,直接返回原始输入流
 | 
			
		||||
@@ -98,4 +91,14 @@ public class RepeatReadRequestWrapper extends HttpServletRequestWrapper {
 | 
			
		||||
        }
 | 
			
		||||
        return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(cachedBody), StandardCharsets.UTF_8));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 检查是否为文件上传请求
 | 
			
		||||
     * 
 | 
			
		||||
     * @param request 请求对象
 | 
			
		||||
     * @return 是否为文件上传请求
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isMultipartContent(HttpServletRequest request) {
 | 
			
		||||
        return request.getContentType() != null && request.getContentType().toLowerCase().startsWith("multipart/");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -31,14 +31,16 @@ import java.nio.charset.StandardCharsets;
 | 
			
		||||
 * 支持缓存响应内容,便于日志记录和后续处理 (不缓存SSE)
 | 
			
		||||
 *
 | 
			
		||||
 * @author echo
 | 
			
		||||
 * @since 2025/03/25 11:11
 | 
			
		||||
 **/
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 2.10.0
 | 
			
		||||
 */
 | 
			
		||||
public class RepeatReadResponseWrapper extends HttpServletResponseWrapper {
 | 
			
		||||
 | 
			
		||||
    private final ByteArrayOutputStream cachedOutputStream = new ByteArrayOutputStream();
 | 
			
		||||
    private final PrintWriter writer = new PrintWriter(cachedOutputStream, true);
 | 
			
		||||
 | 
			
		||||
    // 是否为流式响应
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否为流式响应
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isStreamingResponse = false;
 | 
			
		||||
 | 
			
		||||
    public RepeatReadResponseWrapper(HttpServletResponse response) {
 | 
			
		||||
@@ -67,8 +69,8 @@ public class RepeatReadResponseWrapper extends HttpServletResponseWrapper {
 | 
			
		||||
    @Override
 | 
			
		||||
    public ServletOutputStream getOutputStream() throws IOException {
 | 
			
		||||
        checkStreamingResponse();
 | 
			
		||||
        // 对于 SSE 流式响应,直接返回原始响应流,不做额外处理
 | 
			
		||||
        if (isStreamingResponse) {
 | 
			
		||||
            // 对于 SSE 流式响应,直接返回原始响应流,不做额外处理
 | 
			
		||||
            return super.getOutputStream();
 | 
			
		||||
        }
 | 
			
		||||
        return new ServletOutputStream() {
 | 
			
		||||
@@ -108,6 +110,11 @@ public class RepeatReadResponseWrapper extends HttpServletResponseWrapper {
 | 
			
		||||
        return writer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取缓存的响应内容
 | 
			
		||||
     *
 | 
			
		||||
     * @return 缓存的响应内容
 | 
			
		||||
     */
 | 
			
		||||
    public String getResponseContent() {
 | 
			
		||||
        if (!isStreamingResponse) {
 | 
			
		||||
            writer.flush();
 | 
			
		||||
@@ -116,12 +123,22 @@ public class RepeatReadResponseWrapper extends HttpServletResponseWrapper {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 将缓存的响应内容复制到原始响应中
 | 
			
		||||
     *
 | 
			
		||||
     * @throws IOException IO 异常
 | 
			
		||||
     */
 | 
			
		||||
    public void copyBodyToResponse() throws IOException {
 | 
			
		||||
        if (!isStreamingResponse && cachedOutputStream.size() > 0) {
 | 
			
		||||
            getResponse().getOutputStream().write(cachedOutputStream.toByteArray());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否为流式响应
 | 
			
		||||
     *
 | 
			
		||||
     * @return 是否为流式响应
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isStreamingResponse() {
 | 
			
		||||
        return isStreamingResponse;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -22,8 +22,6 @@ import org.aspectj.lang.ProceedingJoinPoint;
 | 
			
		||||
import org.aspectj.lang.annotation.Around;
 | 
			
		||||
import org.aspectj.lang.annotation.Aspect;
 | 
			
		||||
import org.aspectj.lang.annotation.Pointcut;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import org.springframework.web.context.request.RequestContextHolder;
 | 
			
		||||
import org.springframework.web.context.request.ServletRequestAttributes;
 | 
			
		||||
import top.continew.starter.log.handler.LogHandler;
 | 
			
		||||
@@ -44,7 +42,6 @@ import java.time.Instant;
 | 
			
		||||
@Aspect
 | 
			
		||||
public class AccessLogAspect {
 | 
			
		||||
 | 
			
		||||
    private static final Logger log = LoggerFactory.getLogger(AccessLogAspect.class);
 | 
			
		||||
    private final LogProperties logProperties;
 | 
			
		||||
    private final LogHandler logHandler;
 | 
			
		||||
 | 
			
		||||
@@ -113,7 +110,8 @@ public class AccessLogAspect {
 | 
			
		||||
        HttpServletRequest request = attributes.getRequest();
 | 
			
		||||
        HttpServletResponse response = attributes.getResponse();
 | 
			
		||||
        try {
 | 
			
		||||
            logHandler.processAccessLogStartReq(AccessLogContext.builder()
 | 
			
		||||
            // 开始访问日志记录
 | 
			
		||||
            logHandler.accessLogStart(AccessLogContext.builder()
 | 
			
		||||
                .startTime(startTime)
 | 
			
		||||
                .request(new RecordableServletHttpRequest(request))
 | 
			
		||||
                .properties(logProperties)
 | 
			
		||||
@@ -121,7 +119,7 @@ public class AccessLogAspect {
 | 
			
		||||
            return joinPoint.proceed();
 | 
			
		||||
        } finally {
 | 
			
		||||
            Instant endTime = Instant.now();
 | 
			
		||||
            logHandler.processAccessLogEndReq(AccessLogContext.builder()
 | 
			
		||||
            logHandler.accessLogFinish(AccessLogContext.builder()
 | 
			
		||||
                .endTime(endTime)
 | 
			
		||||
                .response(new RecordableServletHttpResponse(response, response.getStatus()))
 | 
			
		||||
                .build());
 | 
			
		||||
 
 | 
			
		||||
@@ -42,6 +42,7 @@ import java.net.URISyntaxException;
 | 
			
		||||
 * @author Venil Noronha(Spring Boot Actuator)
 | 
			
		||||
 * @author Madhura Bhave(Spring Boot Actuator)
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @author echo
 | 
			
		||||
 * @since 1.1.0
 | 
			
		||||
 */
 | 
			
		||||
public class LogFilter extends OncePerRequestFilter implements Ordered {
 | 
			
		||||
@@ -66,15 +67,15 @@ public class LogFilter extends OncePerRequestFilter implements Ordered {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        boolean isMatch = logProperties.isMatch(request.getRequestURI());
 | 
			
		||||
        boolean isExcludeUri = logProperties.isMatch(request.getRequestURI());
 | 
			
		||||
 | 
			
		||||
        // 处理可重复读取的请求
 | 
			
		||||
        HttpServletRequest requestWrapper = (isMatch || !this.isRequestWrapper(request))
 | 
			
		||||
        HttpServletRequest requestWrapper = (isExcludeUri || !this.isRequestWrapper(request))
 | 
			
		||||
            ? request
 | 
			
		||||
            : new RepeatReadRequestWrapper(request);
 | 
			
		||||
 | 
			
		||||
        // 处理可重复读取的响应
 | 
			
		||||
        HttpServletResponse responseWrapper = (isMatch || !this.isResponseWrapper(response))
 | 
			
		||||
        HttpServletResponse responseWrapper = (isExcludeUri || !this.isResponseWrapper(response))
 | 
			
		||||
            ? response
 | 
			
		||||
            : new RepeatReadResponseWrapper(response);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -171,11 +171,10 @@ public abstract class AbstractLogHandler implements LogHandler {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void processAccessLogStartReq(AccessLogContext accessLogContext) {
 | 
			
		||||
    public void accessLogStart(AccessLogContext accessLogContext) {
 | 
			
		||||
        AccessLogProperties properties = accessLogContext.getProperties().getAccessLog();
 | 
			
		||||
        // 是否需要打印 规则: 是否打印开关 或 放行路径
 | 
			
		||||
        if (!properties.isPrint() || accessLogContext.getProperties()
 | 
			
		||||
            .getAccessLog()
 | 
			
		||||
            .isMatch(accessLogContext.getRequest().getPath())) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -184,22 +183,23 @@ public abstract class AbstractLogHandler implements LogHandler {
 | 
			
		||||
        RecordableHttpRequest request = accessLogContext.getRequest();
 | 
			
		||||
        String path = request.getPath();
 | 
			
		||||
        String param = AccessLogUtils.getParam(request, properties);
 | 
			
		||||
        log.info(param != null ? "[Start] [{}] {} {}" : "[Start] [{}] {}", request.getMethod(), path, param);
 | 
			
		||||
        log.info(param != null ? "[Start] [{}] {} param: {}" : "[Start] [{}] {}", request.getMethod(), path, param);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void processAccessLogEndReq(AccessLogContext accessLogContext) {
 | 
			
		||||
    public void accessLogFinish(AccessLogContext accessLogContext) {
 | 
			
		||||
        AccessLogContext logContext = logContextThread.get();
 | 
			
		||||
        if (ObjectUtil.isNotEmpty(logContext)) {
 | 
			
		||||
            try {
 | 
			
		||||
                RecordableHttpRequest request = logContext.getRequest();
 | 
			
		||||
                RecordableHttpResponse response = accessLogContext.getResponse();
 | 
			
		||||
                Duration timeTaken = Duration.between(logContext.getStartTime(), accessLogContext.getEndTime());
 | 
			
		||||
                log.info("[End] [{}] {} {} {}ms", request.getMethod(), request.getPath(), response
 | 
			
		||||
                    .getStatus(), timeTaken.toMillis());
 | 
			
		||||
            } finally {
 | 
			
		||||
                logContextThread.remove();
 | 
			
		||||
            }
 | 
			
		||||
        if (ObjectUtil.isEmpty(logContext)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        try {
 | 
			
		||||
            RecordableHttpRequest request = logContext.getRequest();
 | 
			
		||||
            RecordableHttpResponse response = accessLogContext.getResponse();
 | 
			
		||||
            Duration timeTaken = Duration.between(logContext.getStartTime(), accessLogContext.getEndTime());
 | 
			
		||||
            log.info("[End] [{}] {} {} {}ms", request.getMethod(), request.getPath(), response.getStatus(), timeTaken
 | 
			
		||||
                .toMillis());
 | 
			
		||||
        } finally {
 | 
			
		||||
            logContextThread.remove();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ import java.util.Set;
 | 
			
		||||
 * 日志处理器
 | 
			
		||||
 *
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @author echo
 | 
			
		||||
 * @since 2.8.0
 | 
			
		||||
 */
 | 
			
		||||
public interface LogHandler {
 | 
			
		||||
@@ -100,16 +101,18 @@ public interface LogHandler {
 | 
			
		||||
    Set<Include> getIncludes(Set<Include> includes, Method targetMethod, Class<?> targetClass);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 处理访问日志开始请求
 | 
			
		||||
     * 开始访问日志记录
 | 
			
		||||
     *
 | 
			
		||||
     * @param accessLogContext 访问日志上下文
 | 
			
		||||
     * @since 2.10.0
 | 
			
		||||
     */
 | 
			
		||||
    void processAccessLogStartReq(AccessLogContext accessLogContext);
 | 
			
		||||
    void accessLogStart(AccessLogContext accessLogContext);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 处理访问日志 结束请求
 | 
			
		||||
     * 结束访问日志记录
 | 
			
		||||
     *
 | 
			
		||||
     * @param accessLogContext 访问日志上下文
 | 
			
		||||
     * @since 2.10.0
 | 
			
		||||
     */
 | 
			
		||||
    void processAccessLogEndReq(AccessLogContext accessLogContext);
 | 
			
		||||
    void accessLogFinish(AccessLogContext accessLogContext);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ import java.util.Map;
 | 
			
		||||
 * @author Andy Wilkinson(Spring Boot Actuator)
 | 
			
		||||
 * @author Phillip Webb(Spring Boot Actuator)
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @author echo
 | 
			
		||||
 * @see RecordableHttpResponse
 | 
			
		||||
 * @since 1.1.0
 | 
			
		||||
 */
 | 
			
		||||
@@ -45,11 +46,13 @@ public interface RecordableHttpRequest {
 | 
			
		||||
    URI getUrl();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取 IP
 | 
			
		||||
     * 获取路径
 | 
			
		||||
     * <p>/foo/bar</p>
 | 
			
		||||
     *
 | 
			
		||||
     * @return IP
 | 
			
		||||
     * @return 路径
 | 
			
		||||
     * @since 2.10.0
 | 
			
		||||
     */
 | 
			
		||||
    String getIp();
 | 
			
		||||
    String getPath();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取请求头
 | 
			
		||||
@@ -73,9 +76,9 @@ public interface RecordableHttpRequest {
 | 
			
		||||
    Map<String, Object> getParam();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取路径 - 格式 /system/dept
 | 
			
		||||
     * 获取 IP
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@link String }
 | 
			
		||||
     * @return IP
 | 
			
		||||
     */
 | 
			
		||||
    String getPath();
 | 
			
		||||
    String getIp();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,8 @@ import java.util.Map;
 | 
			
		||||
 *
 | 
			
		||||
 * @author Andy Wilkinson(Spring Boot Actuator)
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @author echo
 | 
			
		||||
 * @since 1.1.0
 | 
			
		||||
 */
 | 
			
		||||
public final class RecordableServletHttpRequest implements RecordableHttpRequest {
 | 
			
		||||
 | 
			
		||||
@@ -66,8 +68,8 @@ public final class RecordableServletHttpRequest implements RecordableHttpRequest
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getIp() {
 | 
			
		||||
        return JakartaServletUtil.getClientIP(request);
 | 
			
		||||
    public String getPath() {
 | 
			
		||||
        return request.getRequestURI();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -90,8 +92,8 @@ public final class RecordableServletHttpRequest implements RecordableHttpRequest
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getPath() {
 | 
			
		||||
        return request.getRequestURI();
 | 
			
		||||
    public String getIp() {
 | 
			
		||||
        return JakartaServletUtil.getClientIP(request);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private StringBuilder appendQueryString(String queryString) {
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,8 @@ import java.util.Map;
 | 
			
		||||
 *
 | 
			
		||||
 * @author Andy Wilkinson(Spring Boot Actuator)
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @author echo
 | 
			
		||||
 * @since 1.1.0
 | 
			
		||||
 */
 | 
			
		||||
public final class RecordableServletHttpResponse implements RecordableHttpResponse {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ import java.time.Instant;
 | 
			
		||||
 * 访问日志上下文
 | 
			
		||||
 *
 | 
			
		||||
 * @author echo
 | 
			
		||||
 * @since 2.8.3
 | 
			
		||||
 * @since 2.10.0
 | 
			
		||||
 */
 | 
			
		||||
public class AccessLogContext {
 | 
			
		||||
 | 
			
		||||
@@ -90,7 +90,11 @@ public class AccessLogContext {
 | 
			
		||||
        return new Builder();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 访问日志上下文构建者
 | 
			
		||||
     */
 | 
			
		||||
    public static class Builder {
 | 
			
		||||
 | 
			
		||||
        private Instant startTime;
 | 
			
		||||
        private Instant endTime;
 | 
			
		||||
        private RecordableHttpRequest request;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,76 +16,71 @@
 | 
			
		||||
 | 
			
		||||
package top.continew.starter.log.model;
 | 
			
		||||
 | 
			
		||||
import top.continew.starter.web.util.SpringWebUtils;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 访问日志输出配置
 | 
			
		||||
 * 访问日志配置属性
 | 
			
		||||
 *
 | 
			
		||||
 * @author echo
 | 
			
		||||
 * @since 2.8.3
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 2.10.0
 | 
			
		||||
 */
 | 
			
		||||
public class AccessLogProperties {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否打印日志,开启后可打印访问日志(类似于 Nginx access log)
 | 
			
		||||
     * 是否打印访问日志(类似于 Nginx access log)
 | 
			
		||||
     * <p>
 | 
			
		||||
     * 不记录日志也支持开启打印访问日志
 | 
			
		||||
     * 不记录请求日志也支持开启打印访问日志
 | 
			
		||||
     * </p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isPrint = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 放行路由
 | 
			
		||||
     * 是否打印请求参数(body/query/form)
 | 
			
		||||
     * <p>开启后,访问日志会打印请求参数</p>
 | 
			
		||||
     */
 | 
			
		||||
    private List<String> excludePatterns = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否记录请求参数(body/query/form)
 | 
			
		||||
     * <p>开启后会在日志中输出请求参数</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isReqParams = false;
 | 
			
		||||
    private boolean isPrintRequestParam = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否自动截断超长参数值(如 base64、大文本)
 | 
			
		||||
     * <p>开启后会对超过指定长度的参数值进行截断处理</p>
 | 
			
		||||
     * <p>开启后,超过指定长度的参数值将会自动截断处理</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean truncateLongParams = false;
 | 
			
		||||
    private boolean longParamTruncate = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 超长参数检测阈值(单位:字符)
 | 
			
		||||
     * <p>当参数值长度超过此值时,触发截断规则</p>
 | 
			
		||||
     * <p>默认:2000</p>
 | 
			
		||||
     * <p>默认:2000,仅在 {@link #longParamTruncate} 启用时生效</p>
 | 
			
		||||
     */
 | 
			
		||||
    private int ultraLongParamThreshold = 2000;
 | 
			
		||||
    private int longParamThreshold = 2000;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 超长参数最大展示长度(单位:字符)
 | 
			
		||||
     * <p>当参数超过ultraLongParamThreshold时,强制截断到此长度</p>
 | 
			
		||||
     * <p>默认:50</p>
 | 
			
		||||
     * 超长参数最大保留长度(单位:字符)
 | 
			
		||||
     * <p>当参数超过 {@link #longParamThreshold} 时,强制截断到此长度</p>
 | 
			
		||||
     * <p>默认:50,仅在 {@link #longParamTruncate} 启用时生效</p>
 | 
			
		||||
     */
 | 
			
		||||
    private int ultraLongParamMaxLength = 50;
 | 
			
		||||
    private int longParamMaxLength = 50;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 截断后追加的后缀符号(如配置 "..." 会让截断内容更直观)
 | 
			
		||||
     * <p>建议配置 3-5 个非占宽字符,默认为空不追加</p>
 | 
			
		||||
     * <p>建议配置 3-5 个非占宽字符,默认为 ...</p>
 | 
			
		||||
     * <p>仅在 {@link #longParamTruncate} 启用时生效</p>
 | 
			
		||||
     */
 | 
			
		||||
    private String truncateSuffix = "...";
 | 
			
		||||
    private String longParamSuffix = "...";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否过滤敏感参数
 | 
			
		||||
     * <p>开启后会对敏感参数进行过滤,默认不过滤</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isSensitiveParams = false;
 | 
			
		||||
    private boolean isParamSensitive = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 敏感参数字段列表(如:password,token,idCard)
 | 
			
		||||
     * <p>支持精确匹配(区分大小写)</p>
 | 
			
		||||
     * <p>示例值:password,oldPassword</p>
 | 
			
		||||
     */
 | 
			
		||||
    private List<String> sensitiveParamList = new ArrayList<>();
 | 
			
		||||
    private List<String> sensitiveParams = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    public boolean isPrint() {
 | 
			
		||||
        return isPrint;
 | 
			
		||||
@@ -95,77 +90,59 @@ public class AccessLogProperties {
 | 
			
		||||
        isPrint = print;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<String> getExcludePatterns() {
 | 
			
		||||
        return excludePatterns;
 | 
			
		||||
    public boolean isPrintRequestParam() {
 | 
			
		||||
        return isPrintRequestParam;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setExcludePatterns(List<String> excludePatterns) {
 | 
			
		||||
        this.excludePatterns = excludePatterns;
 | 
			
		||||
    public void setPrintRequestParam(boolean printRequestParam) {
 | 
			
		||||
        isPrintRequestParam = printRequestParam;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isReqParams() {
 | 
			
		||||
        return isReqParams;
 | 
			
		||||
    public boolean isLongParamTruncate() {
 | 
			
		||||
        return longParamTruncate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setReqParams(boolean reqParams) {
 | 
			
		||||
        isReqParams = reqParams;
 | 
			
		||||
    public void setLongParamTruncate(boolean longParamTruncate) {
 | 
			
		||||
        this.longParamTruncate = longParamTruncate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isTruncateLongParams() {
 | 
			
		||||
        return truncateLongParams;
 | 
			
		||||
    public int getLongParamThreshold() {
 | 
			
		||||
        return longParamThreshold;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTruncateLongParams(boolean truncateLongParams) {
 | 
			
		||||
        this.truncateLongParams = truncateLongParams;
 | 
			
		||||
    public void setLongParamThreshold(int longParamThreshold) {
 | 
			
		||||
        this.longParamThreshold = longParamThreshold;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getUltraLongParamThreshold() {
 | 
			
		||||
        return ultraLongParamThreshold;
 | 
			
		||||
    public int getLongParamMaxLength() {
 | 
			
		||||
        return longParamMaxLength;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setUltraLongParamThreshold(int ultraLongParamThreshold) {
 | 
			
		||||
        this.ultraLongParamThreshold = ultraLongParamThreshold;
 | 
			
		||||
    public void setLongParamMaxLength(int longParamMaxLength) {
 | 
			
		||||
        this.longParamMaxLength = longParamMaxLength;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getUltraLongParamMaxLength() {
 | 
			
		||||
        return ultraLongParamMaxLength;
 | 
			
		||||
    public String getLongParamSuffix() {
 | 
			
		||||
        return longParamSuffix;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setUltraLongParamMaxLength(int ultraLongParamMaxLength) {
 | 
			
		||||
        this.ultraLongParamMaxLength = ultraLongParamMaxLength;
 | 
			
		||||
    public void setLongParamSuffix(String longParamSuffix) {
 | 
			
		||||
        this.longParamSuffix = longParamSuffix;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getTruncateSuffix() {
 | 
			
		||||
        return truncateSuffix;
 | 
			
		||||
    public boolean isParamSensitive() {
 | 
			
		||||
        return isParamSensitive;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTruncateSuffix(String truncateSuffix) {
 | 
			
		||||
        this.truncateSuffix = truncateSuffix;
 | 
			
		||||
    public void setParamSensitive(boolean paramSensitive) {
 | 
			
		||||
        isParamSensitive = paramSensitive;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isSensitiveParams() {
 | 
			
		||||
        return isSensitiveParams;
 | 
			
		||||
    public List<String> getSensitiveParams() {
 | 
			
		||||
        return sensitiveParams;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSensitiveParams(boolean sensitiveParams) {
 | 
			
		||||
        isSensitiveParams = sensitiveParams;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<String> getSensitiveParamList() {
 | 
			
		||||
        return sensitiveParamList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSensitiveParamList(List<String> sensitiveParamList) {
 | 
			
		||||
        this.sensitiveParamList = sensitiveParamList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否匹配放行路由
 | 
			
		||||
     *
 | 
			
		||||
     * @param uri 请求 URI
 | 
			
		||||
     * @return 是否匹配
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isMatch(String uri) {
 | 
			
		||||
        return this.getExcludePatterns().stream().anyMatch(pattern -> SpringWebUtils.isMatch(uri, pattern));
 | 
			
		||||
    public void setSensitiveParams(List<String> sensitiveParams) {
 | 
			
		||||
        this.sensitiveParams = sensitiveParams;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,14 +26,14 @@ import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 访问日志工具类
 | 
			
		||||
 *
 | 
			
		||||
 * @author echo
 | 
			
		||||
 * @since 2025/03/25 19:16
 | 
			
		||||
 **/
 | 
			
		||||
 * @author Charles7c
 | 
			
		||||
 * @since 2.10.0
 | 
			
		||||
 */
 | 
			
		||||
public class AccessLogUtils {
 | 
			
		||||
 | 
			
		||||
    public AccessLogUtils() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取参数信息
 | 
			
		||||
     *
 | 
			
		||||
@@ -42,8 +42,8 @@ public class AccessLogUtils {
 | 
			
		||||
     * @return {@link String }
 | 
			
		||||
     */
 | 
			
		||||
    public static String getParam(RecordableHttpRequest request, AccessLogProperties properties) {
 | 
			
		||||
        // 是否需要输出参数
 | 
			
		||||
        if (!properties.isReqParams()) {
 | 
			
		||||
        // 是否需要打印请求参数
 | 
			
		||||
        if (!properties.isPrintRequestParam()) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -54,16 +54,16 @@ public class AccessLogUtils {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 是否需要对特定入参脱敏
 | 
			
		||||
        if (properties.isSensitiveParams()) {
 | 
			
		||||
            params = filterSensitiveParams(params, properties.getSensitiveParamList());
 | 
			
		||||
        if (properties.isParamSensitive()) {
 | 
			
		||||
            params = filterSensitiveParams(params, properties.getSensitiveParams());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 是否自动截断超长参数值
 | 
			
		||||
        if (properties.isTruncateLongParams()) {
 | 
			
		||||
            params = truncateLongParams(params, properties.getUltraLongParamThreshold(), properties
 | 
			
		||||
                .getUltraLongParamMaxLength(), properties.getTruncateSuffix());
 | 
			
		||||
        if (properties.isLongParamTruncate()) {
 | 
			
		||||
            params = truncateLongParams(params, properties.getLongParamThreshold(), properties
 | 
			
		||||
                .getLongParamMaxLength(), properties.getLongParamSuffix());
 | 
			
		||||
        }
 | 
			
		||||
        return "param:" + JSONUtil.toJsonStr(params);
 | 
			
		||||
        return JSONUtil.toJsonStr(params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -80,9 +80,7 @@ public class AccessLogUtils {
 | 
			
		||||
 | 
			
		||||
        Map<String, Object> filteredParams = new HashMap<>(params);
 | 
			
		||||
        for (String sensitiveKey : sensitiveParams) {
 | 
			
		||||
            if (filteredParams.containsKey(sensitiveKey)) {
 | 
			
		||||
                filteredParams.put(sensitiveKey, "***");
 | 
			
		||||
            }
 | 
			
		||||
            filteredParams.computeIfPresent(sensitiveKey, (key, value) -> "***");
 | 
			
		||||
        }
 | 
			
		||||
        return filteredParams;
 | 
			
		||||
    }
 | 
			
		||||
@@ -115,4 +113,7 @@ public class AccessLogUtils {
 | 
			
		||||
        }
 | 
			
		||||
        return truncatedParams;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private AccessLogUtils() {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,7 @@ public class LogInterceptor implements HandlerInterceptor {
 | 
			
		||||
                             @NonNull HttpServletResponse response,
 | 
			
		||||
                             @NonNull Object handler) {
 | 
			
		||||
        Instant startTime = Instant.now();
 | 
			
		||||
        logHandler.processAccessLogStartReq(AccessLogContext.builder()
 | 
			
		||||
        logHandler.accessLogStart(AccessLogContext.builder()
 | 
			
		||||
            .startTime(startTime)
 | 
			
		||||
            .request(new RecordableServletHttpRequest(request))
 | 
			
		||||
            .properties(logProperties)
 | 
			
		||||
@@ -84,7 +84,7 @@ public class LogInterceptor implements HandlerInterceptor {
 | 
			
		||||
                                Exception e) {
 | 
			
		||||
        try {
 | 
			
		||||
            Instant endTime = Instant.now();
 | 
			
		||||
            logHandler.processAccessLogEndReq(AccessLogContext.builder()
 | 
			
		||||
            logHandler.accessLogFinish(AccessLogContext.builder()
 | 
			
		||||
                .endTime(endTime)
 | 
			
		||||
                .response(new RecordableServletHttpResponse(response, response.getStatus()))
 | 
			
		||||
                .build());
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user