Java接口响应超时监控
为什么要监控
服务化接口是提供服务的,接口正确性、稳定性是最最重要的,在保证正确的同时需要尽量提高接口响应时间。
有的团队会有专门的工具来对系统响应时间、吞吐量做监控,但如果团队没有这种“待遇”就需要自己来做一些工具为自己的代码提供服务。
自己动手,丰衣足食
AOP + Annotation 简陋实现,能达到目的
AOP : 使用环绕方式对接口拦截,在拦截接口前后记录时间最后计算用时
Annotation : 自定义注解在接口上设置超时时间(timeout)和超时是否发送邮件选项(emailIfTimeout)
通过对接口实际执行时间和配置的超时时间比较,系统可以计算出接口是否超时,此时可使用日志(或其他能通知到开发人员的方式)记录具体哪个接口、什么参数以及执行时间
注解可以提供更多的选项,来为自己接口服务,比如支持注解到类上,批量为接口设置了默认超时时间、支持日志中显示的处理方法名称 等等...
代码实施
接口Annotation定义
/** * 接口自定义属性 * * @author tianshu on 16/8/30 下午4:55. */ @Target(value = {ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface InterfaceProperty { /** * 接口超时时间,单位毫秒.默认值100毫秒 * @return 设置的超时时间 */ int timeout() default 400; /** * 当接口响应超时时,是否发送邮件.默认发送 * @return 返回ture需要发送邮件 */ boolean emailIfTimeout() default true; }
AOP实现
/** * @author tianshu on 16/1/28 下午10:35. */ @Component @Aspect public class SystemRequestAspect { /** 日志 */ private static final Logger LOG = LoggerFactory.getLogger(SystemRequestAspect.class); /** 接口超时日志 */ private static final Logger INTERFACE_TIMEOUT_LOG = LoggerFactory.getLogger("INTERFACE_TIMEOUT_LOG"); @Around(value = "execution(* com.xx.xx.xx.xx..*.*(..))", argNames="pjp") public Object validator(ProceedingJoinPoint pjp) throws Throwable { Object[] args = pjp.getArgs(); /** 拦截的方法名称 */ String methodName = pjp.getTarget().getClass().getSimpleName() + "." + pjp.getSignature().getName(); try { long start = System.currentTimeMillis(); Object obj = pjp.proceed(args); long finish = System.currentTimeMillis(); long useTime = finish - start;
/** 接口响应时间监控 */ interfaceUseTimeMonitor(pjp.getTarget().getClass(), pjp.getSignature().getName(), args, useTime); return obj; } catch(Throwable e) {//处理你的异常 } finally {//处理其他 } } /** * 接口响应时间监控 * * @param targetClass 接口实现class * @param methodName 接口方法 * @param args 接口如参 * @param useTime 调用接口实际使用时间 */ private void interfaceUseTimeMonitor(Class targetClass, String methodName, Object[] args, long useTime) { /** 与接口注解最高用时做比较,符合条件发送邮件 */ try { Class[] classArray = new Class[args.length]; for(int i = 0; i < args.length ; ++i) { classArray[i] = args[i].getClass(); } Method method = targetClass.getMethod(methodName, classArray); if(method.isAnnotationPresent(InterfaceProperty.class)) { InterfaceProperty interfaceProperty = method.getAnnotation(InterfaceProperty.class); if(useTime >= interfaceProperty.timeout()) { if(INTERFACE_TIMEOUT_LOG.isInfoEnabled()) { INTERFACE_TIMEOUT_LOG.info("接口超时,interface:[{}].useTime:[{}].settingUseTime:[{}].traceId:[{}]", new Object[]{targetClass.getSimpleName() + "." + methodName, useTime, interfaceProperty.timeout(), TraceUtils.getTrace()}); } } } } catch(Throwable e) { /** 监控逻辑处理错误什么都不做 */ } } }