AOP统一接口日志打印

550 阅读1分钟

AOP统一接口日志打印

1.前言

在后端开发中,记录接口调用日志作为事后排查问题的关键手段,特别是在生产的环境当中,因为无法通过本地调试获取生成环境,导致无法精确的定位问题的所在。所以,使用AOP来记录接口的入参出参以及调用时间,是运维的必要手段。

2.引入依赖

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
    <scope>runtime</scope>
</dependency><!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.6</version>
    <scope>runtime</scope>
</dependency>

3.日志记录

自处我们使用@Around注解。代码如下

@Aspect
@Component
@Slf4j
public class GlobalLog {
​
    // 定制日志显示颜色
    public static final String CYAN_BOLD = "\033[1;36m";
    public static final String YELLOW = "\033[0;33m";
    public static final String RED_BOLD = "\033[1;31m";
    public static final String RESET = "\033[0m";
​
    @Around("execution(* com.achao.music.controller..*.*(..))")
    public Object globalLog(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        // 获取调用地址
        String uri = getRestApi(method);
        // 获取接口描述(基于swagger3注解)
        String description = getOperationDescription(method);
        // 获取接口入参
        String param = toPrettyJsonString(joinPoint.getArgs());
        log.info("{}统一接口记录--接口{}-{}\n入参:{}{}", YELLOW, uri, description, param, RESET);
        try {
            Object result = joinPoint.proceed();
            log.info("{}统一接口返回记录--接口{}-{}\n入参:{}\n返回:\n{}{}", CYAN_BOLD, uri, description, param, toPrettyJsonString(result), RESET);
            return result;
        } catch (Throwable throwable) {
            log.error("{}统一异常记录--接口{}-{}\n入参:{}\n发生异常{}\n详细:{}{}", RED_BOLD, uri, description, param, throwable.getMessage(), throwable, RESET);
            throw throwable;
        }
    }
​
    private String getRestApi(Method method) {
        Class<?> declaringClass = method.getDeclaringClass();
        RequestMapping requestMapping = declaringClass.getAnnotation(RequestMapping.class);
        // 获取当前方法类中的路劲前缀
        String apiPrefix = requestMapping != null ? Arrays.toString(requestMapping.value()) : "";
        Annotation[] annotations = method.getAnnotations();
        String api = "";
        // 对不同请求的注解获取其路径值
        for (Annotation annotation : annotations) {
            String annotationName = annotation.toString().substring(annotation.toString().lastIndexOf('.'));
            if (annotationName.contains("RequestMapping")) {
                RequestMapping mapping = method.getAnnotation(RequestMapping.class);
                api = apiPrefix + "/" + Arrays.toString(mapping.value());
            }
            if (annotationName.contains("PostMapping")) {
                PostMapping postMapping = method.getAnnotation(PostMapping.class);
                api = apiPrefix + "/" + Arrays.toString(postMapping.value());
            }
            if (annotationName.contains("PutMapping")) {
                PutMapping putMapping = method.getAnnotation(PutMapping.class);
                api =  apiPrefix + "/" + Arrays.toString(putMapping.value());
            }
            if (annotationName.contains("DeleteMapping")) {
                DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
                api =  apiPrefix + "/" + Arrays.toString(deleteMapping.value());
            }
            if (annotationName.contains("GetMapping")) {
                GetMapping getMapping = method.getAnnotation(GetMapping.class);
                api =  apiPrefix + "/" + Arrays.toString(getMapping.value());
            }
        }
        api = api.replaceAll("[\[|\]]", "");
        return api;
    }
​
​
    private String getOperationDescription(Method method) {
        for (Annotation annotation : method.getAnnotations()) {
            String annotationName = annotation.toString().substring(annotation.toString().lastIndexOf('.'));
            if (annotationName.contains("Operation")) {
                Operation operation = method.getAnnotation(Operation.class);
                return operation.description();
            }
        }
        return "";
    }
​
    private String toPrettyJsonString(Object object) {
        return JSON.toJSONString(object, SerializerFeature.PrettyFormat,SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat);
    }
}
​

4.效果展示

image.png