可以用来打印入参出参日志,方便记录,调试
Metrics 用法@Metrics,可以用于类或者方法上
package com.msx.sam.test.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @description: Metrics AOP Logger打印
* @author: MiaoShaoxuan
* @date: 2020-07-15 16:19
**/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface Metrics {
/**
* @description: 成功执行方法后打点
* @author: MiaoShaoxuan
* @date: 2020-07-15 16:21
**/
boolean recordSuccessMetrics() default true;
/**
* 是否在执行方法出错时打点
*
* @return
*/
boolean recordFailMetrics() default true;
/**
* 是否记录请求参数
*
* @return
*/
boolean logParameters() default true;
/**
* 是否记录返回值
*
* @return
*/
boolean logReturn() default true;
/**
* 是否记录异常
*
* @return
*/
boolean logException() default true;
/**
* 是否屏蔽异常返回默认值
*
* @return
*/
boolean ignoreException() default false;
}
实现类代码如下
package com.msx.sam.test.annotation;
import com.fasterxml.jackson.databind.ObjectMapper;
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.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Array;
import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author MiaoShaoxuan
* @Title:
* @Description:
* @date 2020年07月15日 16:22
*/
@Component
@Aspect
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MetricsAspect {
private final Logger log = LoggerFactory.getLogger(getClass());
private static final Map<Class<?>, Object> DEFAULT_VALUES = Stream.of(byte.class, boolean.class, char.class,
int.class, short.class, long.class, float.class, double.class)
.collect(
Collectors.toMap(
clazz -> (Class<?>) clazz,
clazz -> Array.get(Array.newInstance(clazz, 1), 0)));
public static <T> T getDefaultValue(Class<T> clazz) {
return (T) DEFAULT_VALUES.get(clazz);
}
@Autowired
private ObjectMapper objectMapper;
/**
* @description: 监测类上注解类型
* @author: MiaoShaoxuan
* @date: 2020-07-15 17:41
**/
@Pointcut("within(@com.yntendo.sam.test.annotation.Metrics *)")
public void withMetricsAnnotationClass() {
}
/**
* @description: 注解方法上是否有注解
* @author: MiaoShaoxuan
* @date: 2020-07-15 17:41
**/
@Pointcut("@annotation(com.yntendo.sam.test.annotation.Metrics)")
public void withMetricsAnnotationMethod() {
}
// /**
// * @description: 监测Controller是否加上 RestController 注解
// * @author: MiaoShaoxuan
// * @date: 2020-07-15 17:45
// **/
// @Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
// public void controllerBean() {
// }
@Around("withMetricsAnnotationMethod() || withMetricsAnnotationClass() || controllerBean()")
public Object metrics(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// 获取当前方法名和类名
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
String name = String.format("【%s】【%s】", signature.getDeclaringType().toString(), signature.toLongString());
Metrics metrics = signature.getMethod().getAnnotation(Metrics.class);
if (metrics == null) {
metrics = signature.getMethod().getDeclaringClass().getAnnotation(Metrics.class);
}
if (metrics == null) {
@Metrics
final class C {
}
metrics = C.class.getAnnotation(Metrics.class);
}
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes != null) {
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
if (request != null) {
name += String.format("【%s】", request.getRequestURL().toString());
}
}
if (metrics.logParameters()) {
log.info(String.format("【入参日志】调用 %s 的参数是:【%s】", name, objectMapper.writeValueAsString(proceedingJoinPoint.getArgs())));
}
Object returnValue;
Instant start = Instant.now();
try {
returnValue = proceedingJoinPoint.proceed();
if (metrics.recordSuccessMetrics()) {
log.info(String.format("【成功打点】调用 %s 成功,耗时:%d ms", name, Duration.between(start, Instant.now()).toMillis()));
}
} catch (Exception ex) {
if (metrics.recordFailMetrics()) {
log.info(String.format("【失败打点】调用 %s 成功,耗时:%d ms", name, Duration.between(start, Instant.now()).toMillis()));
}
if (metrics.logException()) {
log.error(String.format("【异常日志】调用 %s 出现异常!", name), ex);
}
if (metrics.ignoreException()) {
returnValue = getDefaultValue(signature.getReturnType());
} else {
throw ex;
}
}
if (metrics.logReturn()) {
log.info(String.format("【出参日志】调用 %s 的返回是:【%s】", name, returnValue));
}
return returnValue;
}
}