WANG преди 5 години
родител
ревизия
20ce7ff508

+ 51 - 14
src/main/java/cn/com/qmth/examcloud/web/actuator/ApiStatusInfoCollector.java

@@ -9,6 +9,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Maps;
 
 
 import cn.com.qmth.examcloud.commons.util.Calculator;
 import cn.com.qmth.examcloud.commons.util.Calculator;
+import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
 import cn.com.qmth.examcloud.web.support.ApiInfo;
 import cn.com.qmth.examcloud.web.support.ApiInfo;
 import cn.com.qmth.examcloud.web.support.ApiInfoHolder;
 import cn.com.qmth.examcloud.web.support.ApiInfoHolder;
 
 
@@ -17,8 +18,15 @@ public class ApiStatusInfoCollector {
 
 
 	public synchronized List<ApiStatusInfo> collect(ReportInfo reportInfo) {
 	public synchronized List<ApiStatusInfo> collect(ReportInfo reportInfo) {
 
 
+		// 耗时直方图算法:U:uniform ; B:biased
+		String algorithm = PropertyHolder.getString("$API.statistic.histograms.algorithm", "B");
+		if (!(algorithm.equals("B") || algorithm.equals("U"))) {
+			throw new RuntimeException("histograms algorithm must be 'U' or 'B'");
+		}
+
 		List<HistogramInfo> histogramInfoList = reportInfo.getHistogramInfoList();
 		List<HistogramInfo> histogramInfoList = reportInfo.getHistogramInfoList();
 		List<MeterInfo> meterInfoList = reportInfo.getMeterInfoList();
 		List<MeterInfo> meterInfoList = reportInfo.getMeterInfoList();
+		List<TimerInfo> timerInfoList = reportInfo.getTimerInfoList();
 
 
 		Map<String, MeterInfo> apiErrMeterInfoMap = Maps.newHashMap();
 		Map<String, MeterInfo> apiErrMeterInfoMap = Maps.newHashMap();
 		for (MeterInfo meterInfo : meterInfoList) {
 		for (MeterInfo meterInfo : meterInfoList) {
@@ -30,11 +38,24 @@ public class ApiStatusInfoCollector {
 		}
 		}
 
 
 		Map<String, HistogramInfo> apiHistogramInfoMap = Maps.newHashMap();
 		Map<String, HistogramInfo> apiHistogramInfoMap = Maps.newHashMap();
-		for (HistogramInfo histogramInfo : histogramInfoList) {
-			String key = histogramInfo.getKey();
-			if (key.startsWith(MetricNames.API_HISTOGRAM.name())) {
-				String mapping = key.substring(MetricNames.API_HISTOGRAM.name().length() + 1);
-				apiHistogramInfoMap.put(mapping, histogramInfo);
+		if (algorithm.equals("U")) {
+			for (HistogramInfo histogramInfo : histogramInfoList) {
+				String key = histogramInfo.getKey();
+				if (key.startsWith(MetricNames.API_HISTOGRAM.name())) {
+					String mapping = key.substring(MetricNames.API_HISTOGRAM.name().length() + 1);
+					apiHistogramInfoMap.put(mapping, histogramInfo);
+				}
+			}
+		}
+
+		Map<String, TimerInfo> apiTimerInfoMap = Maps.newHashMap();
+		if (algorithm.equals("B")) {
+			for (TimerInfo timerInfo : timerInfoList) {
+				String key = timerInfo.getKey();
+				if (key.startsWith(MetricNames.API_TIMER.name())) {
+					String mapping = key.substring(MetricNames.API_TIMER.name().length() + 1);
+					apiTimerInfoMap.put(mapping, timerInfo);
+				}
 			}
 			}
 		}
 		}
 
 
@@ -62,17 +83,33 @@ public class ApiStatusInfoCollector {
 				apiStatusInfo.setFiveMinuteRate(cur.getFiveMinuteRate());
 				apiStatusInfo.setFiveMinuteRate(cur.getFiveMinuteRate());
 				apiStatusInfo.setFifteenMinuteRate(cur.getFifteenMinuteRate());
 				apiStatusInfo.setFifteenMinuteRate(cur.getFifteenMinuteRate());
 
 
-				HistogramInfo histogramInfo = apiHistogramInfoMap.get(mapping);
+				if (algorithm.equals("U")) {
+					HistogramInfo histogramInfo = apiHistogramInfoMap.get(mapping);
+
+					apiStatusInfo.setMin(histogramInfo.getMin());
+					apiStatusInfo.setMax(histogramInfo.getMax());
+					apiStatusInfo.setMean(histogramInfo.getMean());
+
+					apiStatusInfo.setP50(histogramInfo.getP50());
+					apiStatusInfo.setP75(histogramInfo.getP75());
+					apiStatusInfo.setP95(histogramInfo.getP95());
+					apiStatusInfo.setP98(histogramInfo.getP98());
+					apiStatusInfo.setP99(histogramInfo.getP99());
+				}
+
+				if (algorithm.equals("B")) {
+					TimerInfo timerInfo = apiTimerInfoMap.get(mapping);
 
 
-				apiStatusInfo.setMin(histogramInfo.getMin());
-				apiStatusInfo.setMax(histogramInfo.getMax());
-				apiStatusInfo.setMean(histogramInfo.getMean());
+					apiStatusInfo.setMin(timerInfo.getMin());
+					apiStatusInfo.setMax(timerInfo.getMax());
+					apiStatusInfo.setMean(timerInfo.getMean());
 
 
-				apiStatusInfo.setP50(histogramInfo.getP50());
-				apiStatusInfo.setP75(histogramInfo.getP75());
-				apiStatusInfo.setP95(histogramInfo.getP95());
-				apiStatusInfo.setP98(histogramInfo.getP98());
-				apiStatusInfo.setP99(histogramInfo.getP99());
+					apiStatusInfo.setP50(timerInfo.getP50());
+					apiStatusInfo.setP75(timerInfo.getP75());
+					apiStatusInfo.setP95(timerInfo.getP95());
+					apiStatusInfo.setP98(timerInfo.getP98());
+					apiStatusInfo.setP99(timerInfo.getP99());
+				}
 
 
 				MeterInfo apiErrMeterInfo = apiErrMeterInfoMap.get(mapping);
 				MeterInfo apiErrMeterInfo = apiErrMeterInfoMap.get(mapping);
 				if (null == apiErrMeterInfo) {
 				if (null == apiErrMeterInfo) {

+ 1 - 1
src/main/java/cn/com/qmth/examcloud/web/actuator/MetricNames.java

@@ -9,6 +9,6 @@ package cn.com.qmth.examcloud.web.actuator;
  */
  */
 public enum MetricNames {
 public enum MetricNames {
 
 
-	API_HISTOGRAM, API_METER, API_ERROR_METER
+	API_TIMER, API_HISTOGRAM, API_METER, API_ERROR_METER
 
 
 }
 }

+ 5 - 0
src/main/java/cn/com/qmth/examcloud/web/enums/HttpServletRequestAttribute.java

@@ -49,6 +49,11 @@ public enum HttpServletRequestAttribute {
 	 */
 	 */
 	$_EXCEPTION_HAPPENED,
 	$_EXCEPTION_HAPPENED,
 
 
+	/**
+	 * METRICS Timer context
+	 */
+	$_METRICS_TIMER_CTX,
+
 	/**
 	/**
 	 * ApiStatisticInterceptor 开始时间
 	 * ApiStatisticInterceptor 开始时间
 	 */
 	 */

+ 51 - 11
src/main/java/cn/com/qmth/examcloud/web/interceptor/ApiStatisticInterceptor.java

@@ -8,14 +8,21 @@ import org.springframework.web.servlet.HandlerInterceptor;
 import com.codahale.metrics.Histogram;
 import com.codahale.metrics.Histogram;
 import com.codahale.metrics.Meter;
 import com.codahale.metrics.Meter;
 import com.codahale.metrics.MetricRegistry;
 import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.Timer;
+import com.codahale.metrics.Timer.Context;
 
 
 import cn.com.qmth.examcloud.web.actuator.MetricNames;
 import cn.com.qmth.examcloud.web.actuator.MetricNames;
 import cn.com.qmth.examcloud.web.actuator.MetricRegistryHolder;
 import cn.com.qmth.examcloud.web.actuator.MetricRegistryHolder;
+import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
 import cn.com.qmth.examcloud.web.enums.HttpServletRequestAttribute;
 import cn.com.qmth.examcloud.web.enums.HttpServletRequestAttribute;
 import cn.com.qmth.examcloud.web.support.ApiInfo;
 import cn.com.qmth.examcloud.web.support.ApiInfo;
 
 
 /**
 /**
- * API统计拦截器
+ * API统计拦截器<br>
+ * Timer 和 Histogram 只能使用一个<br>
+ * Timer 为最近耗时<br>
+ * Histogram 为全局耗时<br>
+ * 
  *
  *
  * @author WANGWEI
  * @author WANGWEI
  * @date 2019年7月24日
  * @date 2019年7月24日
@@ -23,14 +30,20 @@ import cn.com.qmth.examcloud.web.support.ApiInfo;
  */
  */
 public class ApiStatisticInterceptor implements HandlerInterceptor {
 public class ApiStatisticInterceptor implements HandlerInterceptor {
 
 
+	private static String algorithm;
+
+	{
+		// 耗时直方图算法:U:uniform ; B:biased
+		algorithm = PropertyHolder.getString("$API.statistic.histograms.algorithm", "B");
+		if (!(algorithm.equals("B") || algorithm.equals("U"))) {
+			throw new RuntimeException("histograms algorithm must be 'U' or 'B'");
+		}
+	}
+
 	@Override
 	@Override
 	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
 	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
 			Object handler) throws Exception {
 			Object handler) throws Exception {
 
 
-		request.setAttribute(
-				HttpServletRequestAttribute.API_STATISTIC_INTERCEPTOR_START_TIME.name(),
-				System.currentTimeMillis());
-
 		ApiInfo apiInfo = (ApiInfo) request
 		ApiInfo apiInfo = (ApiInfo) request
 				.getAttribute(HttpServletRequestAttribute.$_API_INFO.name());
 				.getAttribute(HttpServletRequestAttribute.$_API_INFO.name());
 
 
@@ -38,6 +51,20 @@ public class ApiStatisticInterceptor implements HandlerInterceptor {
 			return true;
 			return true;
 		}
 		}
 
 
+		// Timer 统计
+		if (algorithm.equals("B")) {
+			Timer timer = MetricRegistryHolder.getDefalut()
+					.timer(MetricRegistry.name(MetricNames.API_TIMER.name(), apiInfo.getMapping()));
+			Context ctx = timer.time();
+			request.setAttribute(HttpServletRequestAttribute.$_METRICS_TIMER_CTX.name(), ctx);
+		}
+
+		if (algorithm.equals("U")) {
+			request.setAttribute(
+					HttpServletRequestAttribute.API_STATISTIC_INTERCEPTOR_START_TIME.name(),
+					System.currentTimeMillis());
+		}
+
 		return true;
 		return true;
 	}
 	}
 
 
@@ -52,14 +79,25 @@ public class ApiStatisticInterceptor implements HandlerInterceptor {
 			return;
 			return;
 		}
 		}
 
 
-		Histogram histogram = MetricRegistryHolder.getDefalut().histogram(
-				MetricRegistry.name(MetricNames.API_HISTOGRAM.name(), apiInfo.getMapping()));
-
-		Long startTime = (Long) request.getAttribute(
-				HttpServletRequestAttribute.API_STATISTIC_INTERCEPTOR_START_TIME.name());
+		// Timer 统计
+		if (algorithm.equals("B")) {
+			Context ctx = (Context) request
+					.getAttribute(HttpServletRequestAttribute.$_METRICS_TIMER_CTX.name());
+			if (null != ctx) {
+				ctx.stop();
+			}
+		}
 
 
-		histogram.update(System.currentTimeMillis() - startTime);
+		// Histogram 统计
+		if (algorithm.equals("U")) {
+			Histogram histogram = MetricRegistryHolder.getDefalut().histogram(
+					MetricRegistry.name(MetricNames.API_HISTOGRAM.name(), apiInfo.getMapping()));
+			Long startTime = (Long) request.getAttribute(
+					HttpServletRequestAttribute.API_STATISTIC_INTERCEPTOR_START_TIME.name());
+			histogram.update(System.currentTimeMillis() - startTime);
+		}
 
 
+		// 失败速率
 		Boolean hasException = (Boolean) request
 		Boolean hasException = (Boolean) request
 				.getAttribute(HttpServletRequestAttribute.$_EXCEPTION_HAPPENED.name());
 				.getAttribute(HttpServletRequestAttribute.$_EXCEPTION_HAPPENED.name());
 
 
@@ -69,9 +107,11 @@ public class ApiStatisticInterceptor implements HandlerInterceptor {
 			apiErrorMeter.mark();
 			apiErrorMeter.mark();
 		}
 		}
 
 
+		// 请求速率
 		Meter apiMeter = MetricRegistryHolder.getDefalut()
 		Meter apiMeter = MetricRegistryHolder.getDefalut()
 				.meter(MetricRegistry.name(MetricNames.API_METER.name(), apiInfo.getMapping()));
 				.meter(MetricRegistry.name(MetricNames.API_METER.name(), apiInfo.getMapping()));
 		apiMeter.mark();
 		apiMeter.mark();
 
 
 	}
 	}
+
 }
 }