mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-09 02:58:38 +08:00
refactor(log): 优化访问日志相关配置属性名称
This commit is contained in:
@@ -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