1、定时一个注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Trace {
boolean signature() default true;
boolean printParams() default true;
boolean printResult() default false;
int maxLength() default -1;
}
2、定时一个切面类
@Component
@Aspect
public class TracerAspect {
@Pointcut("@annotation(xxx.xxx.Trace)")
public void around() {
}
@Around("around() && @annotation(trace)")
public Object aroundTaskLock(ProceedingJoinPoint joinPoint, Trace trace) throws Throwable {
if (trace.signature()) {
log.info("signature: {}", signature(joinPoint, trace.printParams(), trace.plainText(), trace.maxLength()));
}
try {
Object object = joinPoint.proceed();
try {
traceReturn(joinPoint, object, trace);
} catch (Exception e) {
log.info("exception thrown traceReturn: [{}]", object.getClass().getName());
}
return object;
} catch (Throwable e) {
log.info("exception thrown: {}", e.getMessage(), e);
throw e;
}
}
private String signature(JoinPoint joinPoint, boolean printParams, boolean plainText, int maxLength) {
try {
Class<?> targetClass = joinPoint.getTarget().getClass();
CodeSignature signature = (CodeSignature) joinPoint.getSignature();
List<String> params = new ArrayList<>();
if (printParams) {
String[] parameterNames = signature.getParameterNames();
Object[] args = joinPoint.getArgs();
IntStream.range(0, parameterNames.length).forEach(index -> {
Object arg = args[index];
if (!(arg instanceof HttpServletRequest || arg instanceof HttpServletResponse || arg instanceof BindingResult)) {
if (null == arg) {
params.add(parameterNames[index] + "=null");
} else if (arg instanceof MultipartFile) {
params.add(parameterNames[index] = "=multipartFile");
} else if (arg instanceof MultipartFile[]) {
params.add(parameterNames[index] + "=" + ((MultipartFile[]) arg).length + "multipartFiles");
} else if (arg instanceof InputStream) {
params.add(parameterNames[index] + "=inputStream");
} else if (arg instanceof InputStream[]) {
params.add(parameterNames[index] + "=inputStream[]");
} else if (arg instanceof OutputStream) {
params.add(parameterNames[index] + "=outputStream");
} else if (arg instanceof OutputStream[]) {
params.add(parameterNames[index] + "=outputStream]");
} else if (arg instanceof Closeable) {
params.add(parameterNames[index] + "=stream");
} else if (arg instanceof Closeable[]) {
params.add(parameterNames[index] + "=stream[]");
} else {
params.add(parameterNames[index] + "=" + JSONObject.toJSONString(arg));
}
}
});
}
final String paramsStr = printParams ? params.stream().map(param -> {
String p = (maxLength != -1 && maxLength > 0) ? param.substring(0, Math.min(param.length(), maxLength)) : param;
String msg = plainText ? p : stringToHex(p);
return msg;
}).collect(Collectors.joining(", ")) : "";
return FormatUtil.format(printParams ? "{}.{}({})" : "{}.{}", targetClass.getCanonicalName(), signature.getName(), paramsStr);
} catch (Exception e) {
// ignore
}
return "";
}
private void traceReturn(ProceedingJoinPoint joinPoint, Object object, Trace trace) {
CommonUtil.isTrue(trace.printResult(), () -> {
String msg = null == object ? "null" : object instanceof Closeable ? "closeable stream" : JSONObject.toJSONString(object);
msg = trace.maxLength() == -1 ? msg : msg.length() <= trace.maxLength() ? msg : msg.substring(0, trace.maxLength());
msg = trace.plainText() ? msg : stringToHex(msg);
log.info("{} ret result: [{}]", signature(joinPoint, false, true, -1), msg);
});
}
}
3、在需要追踪调用的方法上添加Trace注解
4、注解参数说明:
signature: 是否需要打印方法签名
printParams: 是否需要打印方法参数
printResult:是否需要打印返回参数
maxLength:最大打印长度
5、在参数打印上,如果是流则不会对其进行打印,避免后缀方法对流的使用造成影响。