介绍:

  很多时候会需要提供一些统计记录的,比如某个服务一个月的被调用量、接口的调用次数、成功调用次数等等。

优点:

  使用AOP+Hendler对业务逻辑代码无侵入,完全解耦。通过spring boot自带的健康检查接口(/health)方便、安全。

注意:

  数据没有被持久化,只保存在内存中,重启后数据将被重置。可按需自己实现 

代码:

  AOP:在AOP中调用Handler

@Component
@Aspect
public class ControllerAdvice {
    private static ILogger log = LoggerFactory.getLogger(ControllerAdvice.class);

    @Around("execution(public * *..*controller.*.*(..))")
    public Object handle(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result;
        try {
            Function<ProceedingJoinPoint, AbstractControllerHandler> build = AbstractControllerHandler.getBuild();
            if (null == build) {
                AbstractControllerHandler.registerBuildFunction(DefaultControllerHandler::new);
            }
            build = AbstractControllerHandler.getBuild();
            AbstractControllerHandler controllerHandler = build.apply(proceedingJoinPoint);
            if (null == controllerHandler) {
                log.warn(String.format("The method(%s) do not be handle by controller handler.", proceedingJoinPoint.getSignature().getName()));
                result = proceedingJoinPoint.proceed();
            } else {
                result = controllerHandler.handle();
            }
        } catch (Throwable throwable) {
            RuntimeHealthIndicator.failedRequestCount++;
            log.error(new Exception(throwable), "Unknown exception- -!");

            throw throwable;
        }

        return result;
    }
}

 Handler:执行记录的逻辑

    抽象类:AbstractControllerHandler 

public abstract class AbstractControllerHandler {
    private static ILogger log = LoggerFactory.getLogger(AbstractControllerHandler.class);

    private static Function<ProceedingJoinPoint, AbstractControllerHandler> build;

    public static Function<ProceedingJoinPoint, AbstractControllerHandler> getBuild() {
        return build;
    }

    public static void registerBuildFunction(Function<ProceedingJoinPoint, AbstractControllerHandler> build) {
        Assert.isNotNull(build, "build");

        AbstractControllerHandler.build = build;
    }

    protected ProceedingJoinPoint proceedingJoinPoint;
    protected HttpServletRequest httpServletRequest;
    protected String methodName;
    protected String uri;
    protected String requestBody;
    protected String ip;
    protected Method method;
    protected boolean inDataMasking;
    protected boolean outDataMasking;


    public AbstractControllerHandler(ProceedingJoinPoint proceedingJoinPoint) {
        Assert.isNotNull(proceedingJoinPoint, "proceedingJoinPoint");

        this.proceedingJoinPoint = proceedingJoinPoint;
        Signature signature = this.proceedingJoinPoint.getSignature();
        this.httpServletRequest = this.getHttpServletRequest(this.proceedingJoinPoint.getArgs());
        this.methodName = signature.getName();
        this.uri = null == this.httpServletRequest ? null : this.httpServletRequest.getRequestURI();
        this.requestBody = this.formatParameters(this.proceedingJoinPoint.getArgs());
        this.ip = null == this.httpServletRequest ? "" : CommonHelper.getIp(this.httpServletRequest);
        this.inDataMasking = false;
        this.outDataMasking = false;
        if (signature instanceof MethodSignature) {
            MethodSignature methodSignature = (MethodSignature) signature;
            try {
                this.method = proceedingJoinPoint.getTarget().getClass().getMethod(this.methodName, methodSignature.getParameterTypes());
                if (null != this.method) {
                    LogDataMasking dataMasking = this.method.getDeclaredAnnotation(LogDataMasking.class);
                    if (null != dataMasking) {
                        this.inDataMasking = dataMasking.in();
                        this.outDataMasking = dataMasking.out();
                    }
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }

    public abstract Object handle() throws Throwable;

    protected void logIn() {
        String requestBody = this.requestBody;
        if (this.inDataMasking) {
            requestBody = "Data Masking";
        }
        log.info(String.format("Start-[%s][%s][%s][body: %s]", this.ip, this.uri, this.methodName, requestBody));
    }

    protected void logOut(long elapsedMilliseconds, boolean success, String responseBody) {
        if (success) {
            if (this.outDataMasking) {
                responseBody = "Data Masking";
            }
            log.info(
                    String.format(
                            "Success(%s)-[%s][%s][%s][response body: %s]",
                            elapsedMilliseconds,
                            this.ip,
                            this.uri,
                            this.methodName,
                            responseBody));
        } else {
            log.warn(
                    String.format(
                            "Failed(%s)-[%s][%s][%s][request body: %s][response body: %s]",
                            elapsedMilliseconds,
                            this.ip,
                            this.uri,
                            this.methodName,
                            this.requestBody,
                            responseBody));
        }
    }

    protected HttpServletRequest getHttpServletRequest(Object[] parameters) {
        try {
            if (null != parameters) {
                for (Object parameter : parameters) {
                    if (parameter instanceof HttpServletRequest) {
                        return (HttpServletRequest) parameter;
                    }
                }
            }

            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        } catch (Exception e) {
            log.error(e);

            return null;
        }
    }

    protected String formatParameters(Object[] parameters) {
        if (null == parameters) {
            return null;
        } else {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < parameters.length; i++) {
                Object parameter = parameters[i];
                if (parameter instanceof HttpServletRequest || parameter instanceof HttpServletResponse) {
                    continue;
                }

                stringBuilder.append(String.format("[%s]: %s.", i, JSON.toJSONString(parameter)));
            }

            return stringBuilder.toString();
        }
    }

  实现类:

public class DefaultControllerHandler extends AbstractControllerHandler {
    private static ILogger log = LoggerFactory.getLogger(DefaultControllerHandler.class);
    private static int currentMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;

    public DefaultControllerHandler(ProceedingJoinPoint proceedingJoinPoint) {
        super(proceedingJoinPoint);
    }

    @Override
    public Object handle() throws Throwable {
        long timestamp = System.currentTimeMillis();
        this.logIn();

        ResponseDto responseDto;
        boolean success = false;
        try {
            Object result = proceedingJoinPoint.proceed();
            if (result instanceof ResponseDto) {
                responseDto = (ResponseDto) result;
            } else {
                responseDto = ResponseDto.success(result);
            }
            success = true;
            RuntimeHealthIndicator.successRequestCount++;
        } catch (BusinessException e) {
//            RuntimeHealthIndicator.failedRequestCount++;
            if (this.isDebugLogLevel()) {
                log.error(e);
            }

            responseDto = new ResponseDto<>(e.getCode(), e.getMessage(), null);
        } catch (Exception e) {
            RuntimeHealthIndicator.failedRequestCount++;

            if (this.isDebugLogLevel()) {
                log.error(e);
            }

            responseDto = ResponseDto.failed(ExceptionDefinitions.ServerError, e.getMessage(), null);
        } finally {
            Calendar cale = Calendar.getInstance();
            if (currentMonth != (cale.get(Calendar.MONTH) + 1)) {
                String recodeKey = String.format("%d年%d月",
                        cale.get(Calendar.YEAR), cale.get(Calendar.MONTH) + 1);
                String recodeValue = "successCount:" + RuntimeHealthIndicator.successRequestCount +
                        " failedCount:" + RuntimeHealthIndicator.failedRequestCount;
                RuntimeHealthIndicator.historyRequestRecode.put(recodeKey, recodeValue);
                RuntimeHealthIndicator.successRequestCount = 0;
                RuntimeHealthIndicator.failedRequestCount = 0;
                currentMonth = cale.get(Calendar.MONTH);
            }
        }

        long duration = System.currentTimeMillis() - timestamp;
        RuntimeHealthIndicator.markRestApiInvoked(this.methodName, (int) duration);
        this.logOut(duration, success, JSON.toJSONString(responseDto));

        return responseDto;
    }

    public boolean isDebugLogLevel() {
        return log.isEnabled(LogLevel.DEBUG);
    }
}
View Code

相关文章:

  • 2021-11-30
  • 2022-12-23
  • 2021-09-16
  • 2021-10-19
  • 2022-01-28
  • 2021-12-26
  • 2021-12-26
  • 2021-12-26
猜你喜欢
  • 2021-04-21
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-05-11
  • 2022-12-23
相关资源
相似解决方案