數據統計埋點需求

背景

隨着公司代碼的迭代,有一些垃圾代碼邏輯冗餘在項目中,導致消耗了資源又不好維護。爲了保險,需要在線上統計代碼使用的頻率,剔除無用代碼。

描述

方法便可分爲如下幾種:

  1. 對於確定沒用的代碼,可以先註釋掉,並替換爲error日誌,保證遇到問題及時發現。
  2. 對疑似無用代碼,可以使用統計方法調用次數,運行一段時間,判斷去留。

設計

第一種方法就是,註釋代碼添加日誌,所以我們着重描述第二種情況:

使用 spring aop 進行攔截,注意只能攔截被 ioc 管理的對象

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CountInvokeTimes {
}
@Aspect
@Slf4j
@Component
public class CountInvokedTimesAspect {
    private final RedisUtils redisUtil;

    public CountInvokedTimesAspect(RedisUtils redisUtil) {
        this.redisUtil = redisUtil;
    }

    @Pointcut("@within(com.tao.annotation.CountInvokeTimes) || @annotation(com.tao.annotation.CountInvokeTimes)")
    public void countInvokeTimes() {
    }

    @Around(value = "countInvokeTimes()")
    public Object doAround(ProceedingJoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        Class<?>[] argTypes = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            argTypes[i] = args[i].getClass();
        }
        try {
            String methodName = joinPoint.getSignature().getName();
            Method method = joinPoint.getTarget().getClass().getMethod(methodName, argTypes);
            Class<?> aClass = joinPoint.getTarget().getClass();
            String className  = aClass.getName();
            boolean isClassAnnotationPresent = aClass.isAnnotationPresent(CountInvokeTimes.class);
            boolean isMethodAnnotationPresent = method.isAnnotationPresent(CountInvokeTimes.class);
            if (isClassAnnotationPresent || isMethodAnnotationPresent) {
                // 此處也可以發送mq消息給統計服務
                redisUtil.getRedisTemplate().opsForZSet().incrementScore(RedisConstant.METHOD_STATISTICS, className + "." + methodName, 1);
            }
        } catch (Exception e) {
            log.error("CountInvokedTimesAspect error", e);
        }

        Object object = null;
        try {
            object = joinPoint.proceed();
        } catch (Throwable throwable) {
            log.error("CountInvokedTimesAspect error", throwable);
        }
        return object;
    }
}
 
    @RequestMapping("/getMethodStatistics")
    public String getMethodStatistics() {
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisUtils.getRedisTemplate().opsForZSet().rangeWithScores(RedisConstant.METHOD_STATISTICS, 0, -1);
        return JSON.toJSONString(typedTuples);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章