|
@@ -1,7 +1,8 @@
|
|
|
package com.sckw.log.aspect;
|
|
package com.sckw.log.aspect;
|
|
|
|
|
|
|
|
-import com.alibaba.fastjson.JSON;
|
|
|
|
|
-import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
|
|
+import com.alibaba.fastjson2.JSON;
|
|
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
|
|
+import com.alibaba.fastjson2.filter.ValueFilter;
|
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
@@ -56,9 +57,37 @@ public class LogInfoAspect {
|
|
|
return getResult(p);
|
|
return getResult(p);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 定义最大字符串长度(例如 10000 字符)
|
|
|
|
|
+ private static final int MAX_STR_LEN = 10000;
|
|
|
|
|
+
|
|
|
|
|
+ // 复用 ValueFilter 实例,避免重复创建
|
|
|
|
|
+ private static final ValueFilter TRUNCATE_FILTER = (object, name, value) -> {
|
|
|
|
|
+ if (value instanceof String) {
|
|
|
|
|
+ String str = (String) value;
|
|
|
|
|
+ if (str.length() > MAX_STR_LEN) {
|
|
|
|
|
+ return str.substring(0, MAX_STR_LEN) + "...(truncated)";
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return value;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 安全序列化对象,截断超大字符串
|
|
|
|
|
+ */
|
|
|
|
|
+ private String safeToJSONString(Object obj) {
|
|
|
|
|
+ if (obj == null) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ return JSON.toJSONString(obj, TRUNCATE_FILTER);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ // 如果序列化依然失败,返回简单类型信息
|
|
|
|
|
+ return "Serialization failed: " + e.getMessage() + " - object type: " + obj.getClass().getSimpleName();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private Object getResult(ProceedingJoinPoint p) throws Throwable {
|
|
private Object getResult(ProceedingJoinPoint p) throws Throwable {
|
|
|
Object result = null;
|
|
Object result = null;
|
|
|
- //开始时间
|
|
|
|
|
Date startTime = new Date();
|
|
Date startTime = new Date();
|
|
|
String targetName = p.getTarget().getClass().getName();
|
|
String targetName = p.getTarget().getClass().getName();
|
|
|
String methodName = p.getSignature().getName();
|
|
String methodName = p.getSignature().getName();
|
|
@@ -68,39 +97,39 @@ public class LogInfoAspect {
|
|
|
List<Object> logArgs = stream
|
|
List<Object> logArgs = stream
|
|
|
.filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse)) && !(arg instanceof MultipartFile))
|
|
.filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse)) && !(arg instanceof MultipartFile))
|
|
|
.collect(Collectors.toList());
|
|
.collect(Collectors.toList());
|
|
|
- //过滤后序列化无异常
|
|
|
|
|
- String param = JSON.toJSONString(logArgs);
|
|
|
|
|
|
|
+ // 参数序列化(也可使用安全版本,但通常参数较小)
|
|
|
|
|
+ String param = safeToJSONString(logArgs); // 替换为安全方法
|
|
|
String exception = "";
|
|
String exception = "";
|
|
|
try {
|
|
try {
|
|
|
- //执行结果,返回参数
|
|
|
|
|
result = p.proceed();
|
|
result = p.proceed();
|
|
|
} catch (Throwable e) {
|
|
} catch (Throwable e) {
|
|
|
exception = e.getMessage();
|
|
exception = e.getMessage();
|
|
|
- //异常抛出
|
|
|
|
|
throw e;
|
|
throw e;
|
|
|
} finally {
|
|
} finally {
|
|
|
Date endTime = new Date();
|
|
Date endTime = new Date();
|
|
|
long time = endTime.getTime() - startTime.getTime();
|
|
long time = endTime.getTime() - startTime.getTime();
|
|
|
Boolean slowRequest = (time > 1500L);
|
|
Boolean slowRequest = (time > 1500L);
|
|
|
|
|
|
|
|
|
|
+ // 使用 safeToJSONString 替代直接序列化
|
|
|
|
|
+ String resultJson = safeToJSONString(result);
|
|
|
if (exception != null && !exception.isEmpty()) {
|
|
if (exception != null && !exception.isEmpty()) {
|
|
|
log.error("\nAPI调用异常 - {}.{} \n调用方 - {} \n参数:{} \n结果:{} \n异常:{} \n耗时:{}ms \n慢请求:{}",
|
|
log.error("\nAPI调用异常 - {}.{} \n调用方 - {} \n参数:{} \n结果:{} \n异常:{} \n耗时:{}ms \n慢请求:{}",
|
|
|
- targetName, methodName, callerMethodName, param, JSON.toJSONString(result), exception, time, slowRequest);
|
|
|
|
|
|
|
+ targetName, methodName, callerMethodName, param, resultJson, exception, time, slowRequest);
|
|
|
} else if (slowRequest) {
|
|
} else if (slowRequest) {
|
|
|
log.warn("\nAPI慢请求 - {}.{} \n调用方 - {} \n参数:{} \n结果:{} \n耗时:{}ms \n慢请求:{}",
|
|
log.warn("\nAPI慢请求 - {}.{} \n调用方 - {} \n参数:{} \n结果:{} \n耗时:{}ms \n慢请求:{}",
|
|
|
- targetName, methodName, callerMethodName, param, JSON.toJSONString(result), time, slowRequest);
|
|
|
|
|
|
|
+ targetName, methodName, callerMethodName, param, resultJson, time, slowRequest);
|
|
|
} else {
|
|
} else {
|
|
|
log.info("\nAPI调用成功 - {}.{} \n调用方 - {} \n参数:{} \n结果:{} \n耗时:{}ms",
|
|
log.info("\nAPI调用成功 - {}.{} \n调用方 - {} \n参数:{} \n结果:{} \n耗时:{}ms",
|
|
|
- targetName, methodName, callerMethodName, param, JSON.toJSONString(result), time);
|
|
|
|
|
|
|
+ targetName, methodName, callerMethodName, param, resultJson, time);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 原始详细日志保留为debug级别
|
|
|
|
|
|
|
+ // debug 日志同样使用安全序列化
|
|
|
log.debug("\n接口调用 - {}.{} \n调用方 - {}\nparam={}\nresult={}\nexception={}\n[{}->{}],slowRequest{}=[{}]",
|
|
log.debug("\n接口调用 - {}.{} \n调用方 - {}\nparam={}\nresult={}\nexception={}\n[{}->{}],slowRequest{}=[{}]",
|
|
|
targetName,
|
|
targetName,
|
|
|
methodName,
|
|
methodName,
|
|
|
callerMethodName,
|
|
callerMethodName,
|
|
|
param,
|
|
param,
|
|
|
- JSON.toJSONString(result),
|
|
|
|
|
|
|
+ resultJson,
|
|
|
exception,
|
|
exception,
|
|
|
DateFormatUtils.format(startTime, TIME_PATTERN),
|
|
DateFormatUtils.format(startTime, TIME_PATTERN),
|
|
|
DateFormatUtils.format(endTime, TIME_PATTERN),
|
|
DateFormatUtils.format(endTime, TIME_PATTERN),
|
|
@@ -148,17 +177,16 @@ public void doAfterThrowing(JoinPoint point, Throwable e) throws Throwable {
|
|
|
String targetName = point.getTarget().getClass().getName();
|
|
String targetName = point.getTarget().getClass().getName();
|
|
|
String methodName = point.getSignature().getName();
|
|
String methodName = point.getSignature().getName();
|
|
|
String callerMethodName = getCallerMethodName();
|
|
String callerMethodName = getCallerMethodName();
|
|
|
- //获取用户请求方法的参数并序列化为JSON格式字符串
|
|
|
|
|
StringBuilder params = new StringBuilder();
|
|
StringBuilder params = new StringBuilder();
|
|
|
if (point.getArgs() != null && point.getArgs().length > 0) {
|
|
if (point.getArgs() != null && point.getArgs().length > 0) {
|
|
|
for (int i = 0; i < point.getArgs().length; i++) {
|
|
for (int i = 0; i < point.getArgs().length; i++) {
|
|
|
- Object object = point.getArgs()[i];
|
|
|
|
|
- if (!(object instanceof MultipartFile) && !(object instanceof HttpServletResponse) && !(object instanceof HttpServletRequest)) {
|
|
|
|
|
- params.append(JSONObject.toJSONString(point.getArgs()[i])).append(";");
|
|
|
|
|
|
|
+ Object arg = point.getArgs()[i];
|
|
|
|
|
+ if (!(arg instanceof MultipartFile) && !(arg instanceof HttpServletResponse) && !(arg instanceof HttpServletRequest)) {
|
|
|
|
|
+ // 使用安全序列化
|
|
|
|
|
+ params.append(safeToJSONString(arg)).append(";");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
Date endTime = new Date();
|
|
Date endTime = new Date();
|
|
|
long time = endTime.getTime() - startTime.getTime();
|
|
long time = endTime.getTime() - startTime.getTime();
|
|
|
log.error("\nSERVICE异常 - {}.{} \n调用方 - {} \n参数:{} \n异常:{} \n耗时:{}ms \n时间:[{}->{}]",
|
|
log.error("\nSERVICE异常 - {}.{} \n调用方 - {} \n参数:{} \n异常:{} \n耗时:{}ms \n时间:[{}->{}]",
|