sunny123456

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

SpringBoot AOP异常日志处理 使用AOP+注解的方式进行异常日志的处理

最近公司的一个项目需要将异常日志通过企业微信进行告警,由于消息推送已经有异常处理平台进行处理,现在只需要捕获异常信息,将信息发送到异常处理平台就可以了。可以选择的方案其实有两种,一个是springboot其实有全局异常处理,捕获到异常后可以进行消息推送。另一个就是通过AOP进行处理。因为全局异常处理不够灵活,比如不同的方法可能需要处理的异常类型不同,对不同的方法可能会有特殊的处理等等,最终选择了使用AOP+注解的方式进行异常日志的处理。

异常日志注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ExceptionLogService {
    /**
     * 系统模块名
     * @return
     */
    String moduleName() default "";
    /**
     * 业务名称
     * @return
     */
    String businessName() default "";
    /**
     * 日志前缀
     * @return
     */
    String messagePrefix() default "";
    /**
     * 需要推送消息的异常类型
     * @return
     */
    Class<? extends Throwable>[] exception() default {};
}

参数moduleNamebusinessName主要是为了定位异常位置,可写可不写,messagePrefix可以理解为对异常的说明,同时可以指定需要进行异常日志推送的异常类型,如果不指定则所有的异常都会进行推送。

切面类

@Aspect
@Component
public class ExceptionLogServiceAspect implements Ordered {
    private final static Logger logger= LoggerFactory.getLogger(ExceptionLogServiceAspect.class);
    @Autowired
    MessageService messageService;
    @Pointcut("@annotation(com.test.ExceptionLogService)")
    public void exceptionLogService(){
    }
    @Around("exceptionLogService()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result=null;
        Throwable exception=null;
        MethodSignature signature =(MethodSignature) proceedingJoinPoint.getSignature();
        ExceptionLogService annotation = signature.getMethod().getAnnotation(ExceptionLogService.class);
        String className = proceedingJoinPoint.getTarget().getClass().getSimpleName();
        String methodName = signature.getName();
        try {
            result = proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            //获取需要推送消息的异常类型
            exception = getLogException(annotation, throwable);
            //构建消息内容
            String logContent = buildLogContent(annotation,className,methodName, exception);
            //推送消息到异常处理平台
            messageService.sendErrorMessage(logContent);
            //消息推送完成后将异常抛出,因为对于异常有另外的AOP进行处理,所以只是处理异常日志,然后直接抛出
            exception=throwable;
        }finally {
            if (exception!=null){
                throw exception;
            }
        }
        return result;
    }
    /**
     * 根据ExceptionLogService 注解中的异常类型数组获取需要推送消息的异常类型,如果数组为空则所有的异常都进行消息推送
     * @param annotation
     * @param throwable
     * @return
     */
    private Throwable getLogException( ExceptionLogService annotation,Throwable throwable){
        Class<?>[] exceptions = annotation.exception();
        Throwable exception=null;
        if (exceptions==null || exceptions.length==0){
            exception=throwable;
        }else {
            for (Class<?> clazz : exceptions) {
                if (clazz.isInstance(throwable)){
                    exception=throwable;
                    break;
                }
            }
        }
        return exception;
    }
    /**
     * 构建异常消息内容
     * @param annotation ExceptionLogService注解
     * @param className 发生异常的类名称
     * @param methodName 发生异常的方法名称
     * @param throwable 抛出异常
     * @return 消息内容
     */
    private String buildLogContent(ExceptionLogService annotation, String className, String  methodName, Throwable throwable){
        if (annotation==null||throwable==null){
            return null;
        }
        String moduleName = annotation.moduleName();
        String businessName = annotation.businessName();
        String messagePrefix = annotation.messagePrefix();
        StringBuilder stringBuilder = new StringBuilder();
        if (StringUtils.isNotBlank(moduleName)){
            stringBuilder.append(moduleName).append(" 模块,");
        }
        if (StringUtils.isNotBlank(businessName)){
            stringBuilder.append(businessName).append(" 业务");
        }
        //如果异常消息为空,展示异常类型
        String message = throwable.getMessage();
        boolean isNull=false;
        if (StringUtils.isBlank(message)){
            message = throwable.getClass().getSimpleName();
            isNull=true;
        }
        stringBuilder.append("发生异常:").append(StringUtils.isBlank(messagePrefix) ? "" : messagePrefix);
        stringBuilder.append(isNull ? " 异常类型为:" : " 异常消息为:")
                .append(message).append("。异常位置:").append(className)
                .append(".class >>> ").append(methodName).append("()");
        String logContent = stringBuilder.toString();
        logger.error("AOP异常日志:{}",logContent);
        return logContent;
    }
    @Override
    public int getOrder() {
        return 1;
    }
}

异常消息格式

moduleName 模块,businessName 业务发生异常,异常消息为:异常消息。异常位置:类名.class>>>方法名()

对于异常消息为空的异常将展示异常的类型。

测试

    @ExceptionLogService(moduleName = "测试模块",businessName = "test",exception = {NullPointerException.class})
    @Override
    public String logServiceTest() throws Exception {
        logger.info("testLog");
        throw new NullPointerException();
        return "test";
    }
https://www.cnblogs.com/li956a/p/15108697.html
posted on 2022-10-27 09:52  sunny123456  阅读(944)  评论(0编辑  收藏  举报