如何在微服务的日志中记录每个接口URL、状态码和耗时信息?
一、实现方式
1.直接通过SpringCloud-GateWay 的GlobalFilter实现
2.AOP+反射+自定义注解自己封装
二、具体实现
1.自定义注解
@Target({ElementType.METHOD})//作用在方法上
@Retention(RetentionPolicy.RUNTIME)//运行时生效
public @interface MethodExporter{
//自定义注解只是为了提供切入点
}
2.通用controller
@RestController
@Slf4j
public class MethodExporterController{
//http://localhost:24618/method/list?page=1&rows=7
@GetMapping(value = "/method/list")
@MethodExporter
public Map list(@RequestParam(value = "page",defaultValue = "1") int page,
@RequestParam(value = "rows",defaultValue = "5")int rows){
Map<String,String> result = new LinkedHashMap<>();
result.put("code","200");
result.put("message","success");
//暂停毫秒
try { TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); }
return result;
}
@MethodExporter
@GetMapping(value = "/method/get")
public Map get(){
Map<String,String> result = new LinkedHashMap<>();
result.put("code","404");
result.put("message","not-found");
//暂停毫秒
try { TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); }
return result;
}
@GetMapping(value = "/method/update")
public String update(){
System.out.println("update method without @MethodExporter");
return "ok update";
}
}
3.AOP切面类
@Aspect
@Component
@Slf4j
public class MethodExporterAspect
{
//容器捞鱼,谁带着使用了MethodExporter注解将会触发Around业务逻辑
@Around("@annotation(com.atguigu.interview2.annotations.MethodExporter)")
public Object methodExporter(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
{
Object retValue = null;
long startTime = System.currentTimeMillis();
System.out.println("-----@Around环绕通知AAA-methodExporter");
retValue = proceedingJoinPoint.proceed(); //放行
long endTime = System.currentTimeMillis();
long costTime = endTime - startTime;
//1 获得重载后的方法名
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = signature.getMethod();
//2 确定方法名后获得该方法上面配置的注解标签MyRedisCache
MethodExporter methodExporterAnnotation = method.getAnnotation(MethodExporter.class);
if (methodExporterAnnotation != null)
{
//3 获得方法里面的形参信息
StringBuffer jsonInputParam = new StringBuffer();
Object[] args = proceedingJoinPoint.getArgs();
DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
String[] parameterNames = discoverer.getParameterNames(method);
for (int i = 0; i < parameterNames.length; i++)
{
jsonInputParam.append(parameterNames[i] + "\t" + args[i].toString()+";");
}
//4 将返回结果retValue序列化
String jsonResult = null;
if(retValue != null){
jsonResult = new ObjectMapper().writeValueAsString(retValue);
}else{
jsonResult = "null";
}
log.info("\n方法分析上报中 " +
"\n类名方法名:"+proceedingJoinPoint.getTarget().getClass().getName()+"."+proceedingJoinPoint.getSignature().getName()+"()"+
"\n执行耗时:"+costTime+"毫秒"+
"\n输入参数:"+jsonInputParam+""+
"\n返回结果:"+jsonResult+"" +
"\nover"
);
System.out.println("-----@Around环绕通知BBB-methodExporter");
}
return retValue;
}
}