diff --git a/common/common-rest/pom.xml b/common/common-rest/pom.xml
index ab3a439693d..4bab3535452 100644
--- a/common/common-rest/pom.xml
+++ b/common/common-rest/pom.xml
@@ -46,5 +46,9 @@
log4j
test
+
+ io.servicecomb
+ foundation-metrics
+
diff --git a/common/common-rest/src/main/java/io/servicecomb/common/rest/RestProducerInvocation.java b/common/common-rest/src/main/java/io/servicecomb/common/rest/RestProducerInvocation.java
index 665154c4dfd..628fc5e8b79 100644
--- a/common/common-rest/src/main/java/io/servicecomb/common/rest/RestProducerInvocation.java
+++ b/common/common-rest/src/main/java/io/servicecomb/common/rest/RestProducerInvocation.java
@@ -34,6 +34,9 @@
import io.servicecomb.core.definition.MicroserviceMeta;
import io.servicecomb.core.definition.OperationMeta;
import io.servicecomb.core.invocation.InvocationFactory;
+import io.servicecomb.foundation.metrics.MetricsServoRegistry;
+import io.servicecomb.foundation.metrics.performance.QueueMetrics;
+import io.servicecomb.foundation.metrics.performance.QueueMetricsData;
import io.servicecomb.foundation.vertx.http.HttpServletRequestEx;
import io.servicecomb.foundation.vertx.http.HttpServletResponseEx;
import io.servicecomb.serviceregistry.RegistryUtils;
@@ -64,6 +67,7 @@ public void invoke(Transport transport, HttpServletRequestEx requestEx, HttpServ
protected void scheduleInvocation() {
OperationMeta operationMeta = restOperationMeta.getOperationMeta();
+ QueueMetrics metricsData = initMetrics(operationMeta);
operationMeta.getExecutor().execute(() -> {
synchronized (this.requestEx) {
try {
@@ -76,7 +80,7 @@ protected void scheduleInvocation() {
return;
}
- runOnExecutor();
+ runOnExecutor(metricsData);
} catch (Throwable e) {
LOGGER.error("rest server onRequest error", e);
sendFailResponse(e);
@@ -85,11 +89,13 @@ protected void scheduleInvocation() {
});
}
- protected void runOnExecutor() {
+ protected void runOnExecutor(QueueMetrics metricsData) {
Object[] args = RestCodec.restToArgs(requestEx, restOperationMeta);
this.invocation = InvocationFactory.forProvider(transport.getEndpoint(),
restOperationMeta.getOperationMeta(),
args);
+ this.invocation.setMetricsData(metricsData);
+ updateMetrics();
invoke();
}
@@ -118,6 +124,56 @@ protected RestOperationMeta findRestOperation() {
protected void doInvoke() throws Throwable {
invocation.next(resp -> {
sendResponseQuietly(resp);
+ endMetrics();
+
});
}
+
+ /**
+ * Init the metrics. Note down the queue count and start time.
+ * @param operationMeta Operation data
+ * @return QueueMetrics
+ */
+ private QueueMetrics initMetrics(OperationMeta operationMeta) {
+ QueueMetrics metricsData = new QueueMetrics();
+ metricsData.setQueueStartTime(System.currentTimeMillis());
+ metricsData.setOperQualifiedName(operationMeta.getMicroserviceQualifiedName());
+ QueueMetricsData reqQueue = MetricsServoRegistry.getOrCreateLocalMetrics()
+ .getOrCreateQueueMetrics(operationMeta.getMicroserviceQualifiedName());
+ reqQueue.incrementCountInQueue();
+ return metricsData;
+ }
+
+ /**
+ * Update the queue metrics.
+ */
+ private void updateMetrics() {
+ QueueMetrics metricsData = (QueueMetrics) this.invocation.getMetricsData();
+ if (null != metricsData) {
+ metricsData.setQueueEndTime(System.currentTimeMillis());
+ QueueMetricsData reqQueue = MetricsServoRegistry.getOrCreateLocalMetrics()
+ .getOrCreateQueueMetrics(restOperationMeta.getOperationMeta().getMicroserviceQualifiedName());
+ reqQueue.incrementTotalCount();
+ Long timeInQueue = metricsData.getQueueEndTime() - metricsData.getQueueStartTime();
+ reqQueue.setTotalTime(reqQueue.getTotalTime() + timeInQueue);
+ reqQueue.setMinLifeTimeInQueue(timeInQueue);
+ reqQueue.setMaxLifeTimeInQueue(timeInQueue);
+ reqQueue.decrementCountInQueue();
+ }
+ }
+
+ /**
+ * Prepare the end time of queue metrics.
+ */
+ private void endMetrics() {
+ QueueMetrics metricsData = (QueueMetrics) this.invocation.getMetricsData();
+ if (null != metricsData) {
+ metricsData.setEndOperTime(System.currentTimeMillis());
+ QueueMetricsData reqQueue = MetricsServoRegistry.getOrCreateLocalMetrics()
+ .getOrCreateQueueMetrics(restOperationMeta.getOperationMeta().getMicroserviceQualifiedName());
+ reqQueue.incrementTotalServExecutionCount();
+ reqQueue.setTotalServExecutionTime(
+ reqQueue.getTotalServExecutionTime() + (metricsData.getEndOperTime() - metricsData.getQueueEndTime()));
+ }
+ }
}
diff --git a/common/common-rest/src/test/java/io/servicecomb/common/rest/TestRestProducerInvocation.java b/common/common-rest/src/test/java/io/servicecomb/common/rest/TestRestProducerInvocation.java
index 5751a1e6dec..bd6f6517485 100644
--- a/common/common-rest/src/test/java/io/servicecomb/common/rest/TestRestProducerInvocation.java
+++ b/common/common-rest/src/test/java/io/servicecomb/common/rest/TestRestProducerInvocation.java
@@ -48,6 +48,7 @@
import io.servicecomb.core.definition.OperationMeta;
import io.servicecomb.core.definition.SchemaMeta;
import io.servicecomb.core.executor.ReactiveExecutor;
+import io.servicecomb.foundation.metrics.performance.QueueMetrics;
import io.servicecomb.foundation.vertx.http.AbstractHttpServletRequest;
import io.servicecomb.foundation.vertx.http.HttpServletRequestEx;
import io.servicecomb.foundation.vertx.http.HttpServletResponseEx;
@@ -170,12 +171,14 @@ public void scheduleInvocationNormal(@Mocked OperationMeta operationMeta) {
result = operationMeta;
operationMeta.getExecutor();
result = executor;
+ operationMeta.getMicroserviceQualifiedName();
+ result = "sayHi";
}
};
restProducerInvocation = new MockUp() {
@Mock
- void runOnExecutor() {
+ void runOnExecutor(QueueMetrics metricsData) {
runOnExecutor = true;
}
}.getMockInstance();
@@ -199,6 +202,8 @@ public void scheduleInvocationTimeout(@Mocked OperationMeta operationMeta) {
result = operationMeta;
operationMeta.getExecutor();
result = executor;
+ operationMeta.getMicroserviceQualifiedName();
+ result = "sayHi";
}
};
@@ -229,6 +234,8 @@ public void scheduleInvocationException(@Mocked OperationMeta operationMeta) {
result = operationMeta;
operationMeta.getExecutor();
result = executor;
+ operationMeta.getMicroserviceQualifiedName();
+ result = "sayHi";
requestEx.getAttribute(RestConst.REST_REQUEST);
result = requestEx;
RestCodec.restToArgs(requestEx, restOperationMeta);
@@ -255,6 +262,8 @@ public void runOnExecutor() {
Object[] args = new Object[] {};
new Expectations(RestCodec.class) {
{
+ restOperationMeta.getOperationMeta().getMicroserviceQualifiedName();
+ result = "sayHi";
RestCodec.restToArgs(requestEx, restOperationMeta);
result = args;
}
@@ -266,9 +275,7 @@ void invoke() {
}
}.getMockInstance();
initRestProducerInvocation();
-
- restProducerInvocation.runOnExecutor();
-
+ restProducerInvocation.runOnExecutor(new QueueMetrics());
Assert.assertTrue(invokeNoParam);
Assert.assertSame(args, restProducerInvocation.invocation.getSwaggerArguments());
}
@@ -376,6 +383,8 @@ void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception {
result = schemaMeta;
schemaMeta.getProviderHandlerChain();
result = handlerChain;
+ operationMeta.getMicroserviceQualifiedName();
+ result = "sayHi";
}
};
@@ -388,8 +397,8 @@ protected void sendResponseQuietly(Response response) {
}
};
initRestProducerInvocation();
+ invocation.setMetricsData(new QueueMetrics());
restProducerInvocation.invocation = invocation;
-
restProducerInvocation.doInvoke();
Assert.assertSame(response, result.value);
diff --git a/core/src/main/java/io/servicecomb/core/Invocation.java b/core/src/main/java/io/servicecomb/core/Invocation.java
index 0e78025d1a1..fff523aa816 100644
--- a/core/src/main/java/io/servicecomb/core/Invocation.java
+++ b/core/src/main/java/io/servicecomb/core/Invocation.java
@@ -53,6 +53,17 @@ public class Invocation extends SwaggerInvocation {
// 同步模式:避免应答在网络线程中处理解码等等业务级逻辑
private Executor responseExecutor;
+ //start,end of queue and opertion time after queue for operation level metrics.
+ private Object metricsData;
+
+ public Object getMetricsData() {
+ return metricsData;
+ }
+
+ public void setMetricsData(Object metricsData) {
+ this.metricsData = metricsData;
+ }
+
public Invocation(ReferenceConfig referenceConfig, OperationMeta operationMeta, Object[] swaggerArguments) {
this.invocationType = InvocationType.CONSUMER;
this.referenceConfig = referenceConfig;
@@ -75,7 +86,8 @@ private void init(OperationMeta operationMeta, Object[] swaggerArguments) {
public Transport getTransport() {
if (endpoint == null) {
- throw new IllegalStateException("Endpoint is empty. Forget to configure \"loadbalance\" in consumer handler chain?");
+ throw new IllegalStateException(
+ "Endpoint is empty. Forget to configure \"loadbalance\" in consumer handler chain?");
}
return endpoint.getTransport();
}
diff --git a/foundations/foundation-common/pom.xml b/foundations/foundation-common/pom.xml
index 66f3e9fd450..add23b6ef3f 100644
--- a/foundations/foundation-common/pom.xml
+++ b/foundations/foundation-common/pom.xml
@@ -25,6 +25,14 @@
foundation-common
+
+ com.netflix.servo
+ servo-core
+
+
+ com.netflix.hystrix
+ hystrix-core
+
com.fasterxml.jackson.dataformat
jackson-dataformat-xml
diff --git a/foundations/foundation-metrics/pom.xml b/foundations/foundation-metrics/pom.xml
index 3a10fb74f04..30ddb04ded4 100644
--- a/foundations/foundation-metrics/pom.xml
+++ b/foundations/foundation-metrics/pom.xml
@@ -43,5 +43,13 @@
log4j
test
+
+ io.servicecomb
+ swagger-invocation-core
+
+
+ io.servicecomb
+ java-chassis-core
+
diff --git a/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/MetricsServoRegistry.java b/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/MetricsServoRegistry.java
new file mode 100644
index 00000000000..718becf682a
--- /dev/null
+++ b/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/MetricsServoRegistry.java
@@ -0,0 +1,593 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.servicecomb.foundation.metrics;
+
+import java.io.File;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryUsage;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.ThreadMXBean;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+import org.springframework.beans.factory.InitializingBean;
+
+import com.netflix.config.DynamicPropertyFactory;
+import com.netflix.hystrix.HystrixCommandMetrics;
+import com.netflix.hystrix.HystrixEventType;
+import com.netflix.servo.DefaultMonitorRegistry;
+import com.netflix.servo.annotations.DataSourceType;
+import com.netflix.servo.monitor.AbstractMonitor;
+import com.netflix.servo.monitor.BasicCompositeMonitor;
+import com.netflix.servo.monitor.Gauge;
+import com.netflix.servo.monitor.Informational;
+import com.netflix.servo.monitor.Monitor;
+import com.netflix.servo.monitor.MonitorConfig;
+import com.netflix.servo.publish.BasicMetricFilter;
+import com.netflix.servo.publish.CounterToRateMetricTransform;
+import com.netflix.servo.publish.FileMetricObserver;
+import com.netflix.servo.publish.MetricObserver;
+import com.netflix.servo.publish.MonitorRegistryMetricPoller;
+import com.netflix.servo.publish.PollRunnable;
+import com.netflix.servo.publish.PollScheduler;
+
+import io.servicecomb.foundation.metrics.performance.MetricsDataMonitor;
+import io.servicecomb.foundation.metrics.performance.QueueMetricsData;
+import rx.functions.Func0;
+
+/**
+ * Implementation of metrics preparation and servo registry.
+ */
+public class MetricsServoRegistry implements InitializingBean {
+
+ protected static final ThreadLocal LOCAL_METRICS_MAP = new ThreadLocal<>();
+
+ private static final String METRICS_POLL_TIME = "cse.metrics.polltime";
+
+ private static final String FILENAME = "cse.metrics.file.name";
+
+ private static final String FILEPATH = "cse.metrics.file.path";
+
+ private MetricsDataMonitor localMetrics = new MetricsDataMonitor();
+
+ private static Vector metricsList = new Vector<>();
+
+ /*
+ * Added getter for unit test of local metrics.
+ *
+ * @return Local metric reference
+ */
+ public MetricsDataMonitor getLocalMetrics() {
+ return localMetrics;
+ }
+
+ /**
+ * Get or create local metrics.
+ * @return MetricsDataMonitor
+ */
+ public static MetricsDataMonitor getOrCreateLocalMetrics() {
+ MetricsDataMonitor metricsDataMonitor = LOCAL_METRICS_MAP.get();
+ if (metricsDataMonitor == null) {
+ metricsDataMonitor = new MetricsDataMonitor();
+ LOCAL_METRICS_MAP.set(metricsDataMonitor);
+ metricsList.add(metricsDataMonitor);
+ }
+ return metricsDataMonitor;
+ }
+
+ /**
+ * Get the initial metrics and register with servo.
+ */
+ public void initMetricsPublishing() {
+
+ /* list of monitors */
+ List> monitors = getMetricsMonitors();
+ MonitorConfig commandMetricsConfig = MonitorConfig.builder("metrics").build();
+ BasicCompositeMonitor commandMetricsMonitor = new BasicCompositeMonitor(commandMetricsConfig, monitors);
+ DefaultMonitorRegistry.getInstance().register(commandMetricsMonitor);
+ PollScheduler scheduler = PollScheduler.getInstance();
+ if (!scheduler.isStarted()) {
+ scheduler.start();
+ }
+
+ int metricPoll = DynamicPropertyFactory.getInstance().getIntProperty(METRICS_POLL_TIME, 60).get();
+ String fileName = DynamicPropertyFactory.getInstance().getStringProperty(FILENAME, "metrics").get();
+ String filePath = DynamicPropertyFactory.getInstance().getStringProperty(FILEPATH, ".").get();
+ MetricObserver fileObserver = new FileMetricObserver(fileName, new File(filePath));
+ MetricObserver transform = new CounterToRateMetricTransform(fileObserver, metricPoll, TimeUnit.SECONDS);
+ PollRunnable task = new PollRunnable(new MonitorRegistryMetricPoller(), BasicMetricFilter.MATCH_ALL, transform);
+ scheduler.addPoller(task, metricPoll, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ initMetricsPublishing();
+ }
+
+ /**
+ * Get instance level total requests by comparing the last saved data.
+ */
+ protected final Func0 getTotalReqProvider = new Func0() {
+ @Override
+ public Number call() {
+ Long totalReqProvider = 0L;
+ for (MetricsDataMonitor metricsDataMonitor : metricsList) {
+ totalReqProvider += metricsDataMonitor.getTotalReqProvider();
+ }
+ Long metricValue = totalReqProvider - localMetrics.getTotalReqProvider();
+ localMetrics.setTotalReqProvider(totalReqProvider);
+ return metricValue;
+ }
+ };
+
+ /**
+ * Get instance level total failed requests by comparing the last saved data.
+ */
+ protected final Func0 getTotalFailedReqProvider = new Func0() {
+ @Override
+ public Number call() {
+ Long totalFailedReqProvider = 0L;
+ for (MetricsDataMonitor metricsDataMonitor : metricsList) {
+ totalFailedReqProvider += metricsDataMonitor.getTotalFailReqProvider();
+ }
+ Long metricValue = totalFailedReqProvider - localMetrics.getTotalFailReqProvider();
+ localMetrics.setTotalFailReqProvider(totalFailedReqProvider);
+ return metricValue;
+ }
+ };
+
+ /**
+ * Get instance level total failed requests by comparing the last saved data.
+ */
+ protected final Func0 getTotalReqConsumer = new Func0() {
+ @Override
+ public Number call() {
+ Long totalReqConsumer = 0L;
+ for (MetricsDataMonitor metricsDataMonitor : metricsList) {
+ totalReqConsumer += metricsDataMonitor.getTotalReqConsumer();
+ }
+ Long metricValue = totalReqConsumer - localMetrics.getTotalReqConsumer();
+ localMetrics.setTotalReqConsumer(totalReqConsumer);
+ return metricValue;
+ }
+ };
+
+ /**
+ * Get instance level total failed requests by comparing the last saved data.
+ */
+ protected final Func0 getFailedTotalReqConsumer = new Func0() {
+ @Override
+ public Number call() {
+ Long totalFailedReqConsumer = 0L;
+ for (MetricsDataMonitor metricsDataMonitor : metricsList) {
+ totalFailedReqConsumer += metricsDataMonitor.getTotalFailReqConsumer();
+ }
+ Long metricValue = totalFailedReqConsumer - localMetrics.getTotalFailReqConsumer();
+ localMetrics.setTotalFailReqConsumer(totalFailedReqConsumer);
+ return metricValue;
+ }
+ };
+
+ /**
+ * Get operational level total request and total failed requests by comparing the
+ * last saved data.
+ */
+ protected final Func0 getTotalReqProdOperLevel = new Func0() {
+ @Override
+ public String call() {
+ Map totalMap = new HashMap();
+ Map oldMap = localMetrics.operMetricsTotalReq;
+ Map metricMap = new HashMap();
+ for (MetricsDataMonitor metricsDataMonitor : metricsList) {
+ Collection keySet = metricsDataMonitor.operMetricsTotalReq.keySet();
+ for (String key : keySet) {
+ Long value = totalMap.get(key);
+ if (null == value) {
+ totalMap.put(key, metricsDataMonitor.getOperMetTotalReq(key));
+ } else {
+ totalMap.put(key, metricsDataMonitor.getOperMetTotalReq(key) + value);
+ }
+ }
+ }
+ Collection keySet = totalMap.keySet();
+ for (String key : keySet) {
+ if (oldMap.containsKey(key)) {
+ metricMap.put(key, totalMap.get(key) - oldMap.get(key));
+ } else {
+ metricMap.put(key, totalMap.get(key));
+ }
+ }
+ localMetrics.operMetricsTotalReq.putAll(totalMap);
+ return metricMap.toString();
+ }
+ };
+
+ /**
+ * Get operational level total request and total failed requets by comparing the
+ * last saved data.
+ */
+ protected final Func0 getTotalReqFailProdOperLevel = new Func0() {
+ @Override
+ public String call() {
+ Map totalMap = new HashMap();
+ Map oldMap = localMetrics.operMetricsTotalFailReq;
+ Map metricMap = new HashMap();
+ for (MetricsDataMonitor metricsDataMonitor : metricsList) {
+ Collection keySet = metricsDataMonitor.operMetricsTotalFailReq.keySet();
+ for (String key : keySet) {
+ Long value = totalMap.get(key);
+ if (null == value) {
+ totalMap.put(key, metricsDataMonitor.getOperMetTotalFailReq(key));
+ } else {
+ totalMap.put(key, metricsDataMonitor.getOperMetTotalFailReq(key) + value);
+ }
+ }
+ }
+ Collection keySet = totalMap.keySet();
+ for (String key : keySet) {
+ if (oldMap.containsKey(key)) {
+ metricMap.put(key, totalMap.get(key) - oldMap.get(key));
+ } else {
+ metricMap.put(key, totalMap.get(key));
+ }
+ }
+ localMetrics.operMetricsTotalFailReq.putAll(totalMap);
+ return metricMap.toString();
+ }
+ };
+
+ /**
+ * Get operational level/instance level queue related metrics by comparing the
+ * last saved data.
+ */
+ protected final Func0 getQueueMetrics = new Func0() {
+ @Override
+ public String call() {
+ Map totalMap = new HashMap();
+
+ for (MetricsDataMonitor metricsDataMonitor : metricsList) {
+ Collection keySet = metricsDataMonitor.getQueueMetrics().keySet();
+ for (String key : keySet) {
+ QueueMetricsData value = totalMap.get(key);
+ if (null == value) {
+ totalMap.put(key, metricsDataMonitor.getQueueMetrics().get(key));
+ } else {
+ QueueMetricsData newValue = metricsDataMonitor.getQueueMetrics().get(key);
+ QueueMetricsData totalValue = new QueueMetricsData();
+ totalValue.setCountInQueue(newValue.getCountInQueue() + value.getCountInQueue());
+ totalValue.setTotalTime(newValue.getTotalTime() + value.getTotalTime());
+ totalValue.setTotalCount(newValue.getTotalCount() + value.getTotalCount());
+ totalValue
+ .setTotalServExecutionTime(newValue.getTotalServExecutionTime() + value.getTotalServExecutionTime());
+ totalValue
+ .setTotalServExecutionCount(newValue.getTotalServExecutionCount() + value.getTotalServExecutionCount());
+ if ((value.getMinLifeTimeInQueue() <= 0)
+ || (newValue.getMinLifeTimeInQueue() < value.getMinLifeTimeInQueue())) {
+ totalValue.setMinLifeTimeInQueue(newValue.getMinLifeTimeInQueue());
+ }
+ newValue.resetMinLifeTimeInQueue();
+ if ((value.getMaxLifeTimeInQueue() <= 0)
+ || (newValue.getMaxLifeTimeInQueue() > value.getMaxLifeTimeInQueue())) {
+ totalValue.setMaxLifeTimeInQueue(newValue.getMaxLifeTimeInQueue());
+ }
+ newValue.resetMaxLifeTimeInQueue();
+ totalMap.put(key, totalValue);
+ }
+ }
+ }
+
+ Map oldMap = localMetrics.getQueueMetrics();
+ Map metricMap = new HashMap();
+ Map result = new HashMap<>();
+ Map resultInstancePublishMap = new HashMap<>();
+
+ QueueMetricsData totalValueInstance = new QueueMetricsData();
+
+ Collection keySet = totalMap.keySet();
+ Map resultMap;
+
+ for (String key : keySet) {
+ resultMap = new HashMap<>();
+ if (oldMap.containsKey(key)) {
+ QueueMetricsData newValue = new QueueMetricsData();
+ QueueMetricsData totalValue = totalMap.get(key);
+ QueueMetricsData oldValue = oldMap.get(key);
+ newValue.setCountInQueue(totalValue.getCountInQueue());
+ newValue.setTotalTime(totalValue.getTotalTime() - oldValue.getTotalTime());
+ newValue.setTotalCount(totalValue.getTotalCount() - oldValue.getTotalCount());
+ newValue
+ .setTotalServExecutionTime(totalValue.getTotalServExecutionTime() - oldValue.getTotalServExecutionTime());
+ newValue.setTotalServExecutionCount(
+ totalValue.getTotalServExecutionCount() - oldValue.getTotalServExecutionCount());
+ newValue.setMinLifeTimeInQueue(totalValue.getMinLifeTimeInQueue());
+ newValue.setMaxLifeTimeInQueue(totalValue.getMaxLifeTimeInQueue());
+ metricMap.put(key, newValue);
+ } else {
+ metricMap.put(key, totalMap.get(key));
+ }
+
+ resultMap.put("countInQueue", metricMap.get(key).getCountInQueue().toString());
+
+ long count = metricMap.get(key).getTotalCount();
+ double avgTimeInQueue = 0;
+ if (count > 0) {
+ avgTimeInQueue = metricMap.get(key).getTotalTime() / count;
+ }
+ resultMap.put("AverageTimeInQueue", String.valueOf(avgTimeInQueue));
+ long countService = metricMap.get(key).getTotalServExecutionCount();
+ double avgServiceTimeInQueue = 0;
+ if (countService > 0) {
+ avgServiceTimeInQueue = metricMap.get(key).getTotalServExecutionTime() / countService;
+ }
+ resultMap.put("AverageServiceExecutionTime", String.valueOf(avgServiceTimeInQueue));
+ resultMap.put("MinLifeTimeInQueue", metricMap.get(key).getMinLifeTimeInQueue().toString());
+ resultMap.put("MaxLifeTimeInQueue", metricMap.get(key).getMaxLifeTimeInQueue().toString());
+
+ result.put(key, resultMap.toString());
+
+ //get the all values for instance level.
+ totalValueInstance.setCountInQueue(metricMap.get(key).getCountInQueue());
+ totalValueInstance.setTotalTime(totalValueInstance.getTotalTime() + metricMap.get(key).getTotalTime());
+ totalValueInstance.setTotalCount(totalValueInstance.getTotalCount() + metricMap.get(key).getTotalCount());
+ totalValueInstance
+ .setTotalServExecutionTime(
+ totalValueInstance.getTotalServExecutionTime() + metricMap.get(key).getTotalServExecutionTime());
+ totalValueInstance
+ .setTotalServExecutionCount(
+ totalValueInstance.getTotalServExecutionCount() + metricMap.get(key).getTotalServExecutionCount());
+
+ if (totalValueInstance.getMinLifeTimeInQueue() <= 0
+ || metricMap.get(key).getMinLifeTimeInQueue() < totalValueInstance.getMinLifeTimeInQueue()) {
+ totalValueInstance.setMinLifeTimeInQueue(metricMap.get(key).getMinLifeTimeInQueue());
+ }
+ if (totalValueInstance.getMaxLifeTimeInQueue() <= 0
+ || totalMap.get(key).getMaxLifeTimeInQueue() > totalValueInstance.getMaxLifeTimeInQueue()) {
+ totalValueInstance.setMaxLifeTimeInQueue(metricMap.get(key).getMaxLifeTimeInQueue());
+ }
+
+ localMetrics.setQueueMetrics(new ConcurrentHashMap<>(totalMap));
+ }
+
+ //prepare the result map for instance level.
+ resultInstancePublishMap.put("countInQueue", totalValueInstance.getCountInQueue().toString());
+ long countInst = totalValueInstance.getTotalCount();
+ double avgTimeInQueueIns = 0;
+ if (countInst > 0) {
+ avgTimeInQueueIns = totalValueInstance.getTotalTime() / countInst;
+ }
+ resultInstancePublishMap.put("AverageTimeInQueue", String.valueOf(avgTimeInQueueIns));
+ long countServiceInst = totalValueInstance.getTotalServExecutionCount();
+ double avgServiceTimeInQueueInst = 0;
+ if (countServiceInst > 0) {
+ avgServiceTimeInQueueInst = totalValueInstance.getTotalServExecutionTime() / countServiceInst;
+ }
+ resultInstancePublishMap.put("AverageServiceExecutionTime", String.valueOf(avgServiceTimeInQueueInst));
+ resultInstancePublishMap.put("MinLifeTimeInQueue", totalValueInstance.getMinLifeTimeInQueue().toString());
+ resultInstancePublishMap.put("MaxLifeTimeInQueue", totalValueInstance.getMaxLifeTimeInQueue().toString());
+ result.put("InstanceLevel", resultInstancePublishMap.toString());
+
+ return result.toString();
+ }
+ };
+
+ /**
+ * Get CPU and memory information metrics.
+ */
+ protected final Func0 getCpuAndMemory = new Func0() {
+ @Override
+ public String call() {
+ Map memoryMap = new HashMap<>();
+ OperatingSystemMXBean osMxBean = ManagementFactory.getOperatingSystemMXBean();
+ double cpu = osMxBean.getSystemLoadAverage();
+ memoryMap.put("CPU System Load", String.valueOf(cpu));
+
+ ThreadMXBean threadmxBean = ManagementFactory.getThreadMXBean();
+ int threadCount = threadmxBean.getThreadCount();
+ memoryMap.put("CPU Current Running Threads", String.valueOf(threadCount));
+
+ MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
+ MemoryUsage memHeapUsage = memBean.getHeapMemoryUsage();
+ MemoryUsage nonHeapUsage = memBean.getNonHeapMemoryUsage();
+ memoryMap.put("heapInit", String.valueOf(memHeapUsage.getInit()));
+ memoryMap.put("heapMax", String.valueOf(memHeapUsage.getMax()));
+ memoryMap.put("heapCommit", String.valueOf(memHeapUsage.getCommitted()));
+ memoryMap.put("heapUsed", String.valueOf(memHeapUsage.getUsed()));
+ memoryMap.put("nonHeapInit", String.valueOf(nonHeapUsage.getInit()));
+ memoryMap.put("nonHeapMax", String.valueOf(nonHeapUsage.getMax()));
+ memoryMap.put("nonHeapCommit", String.valueOf(nonHeapUsage.getCommitted()));
+ memoryMap.put("nonHeapUsed", String.valueOf(nonHeapUsage.getUsed()));
+ return memoryMap.toString();
+ }
+ };
+
+ /**
+ * Get TPS and latency for operational and instance level from hystrix.
+ */
+ protected final Func0 getTpsAndLatency = new Func0() {
+ @Override
+ public String call() {
+ Map tpsAndLatencyMap = new HashMap<>();
+ Collection instances = HystrixCommandMetrics.getInstances();
+
+ long insTotalTps = 0;
+ long insTotalLatency = 0;
+ long cumulativeTotalCount = 0;
+
+ for (HystrixCommandMetrics instance : instances) {
+ long successCount = instance.getRollingCount(HystrixEventType.SUCCESS);
+ long failureCount = instance.getRollingCount(HystrixEventType.FAILURE);
+ int operLatency = instance.getExecutionTimeMean();
+ long totalCallCount = successCount + failureCount;
+ cumulativeTotalCount += totalCallCount;
+ int windowTime = instance.getProperties().metricsRollingStatisticalWindowInMilliseconds().get() / 1000;
+ double qpsVal = (double) (totalCallCount) / windowTime;
+ BigDecimal bigDecimal = new BigDecimal(qpsVal);
+ BigDecimal bigDecimalVal = bigDecimal.setScale(1, RoundingMode.HALF_DOWN);
+ Double tpsOper = bigDecimalVal.doubleValue();
+ tpsAndLatencyMap.put("TPS-" + instance.getCommandKey().name(), String.valueOf(tpsOper));
+ tpsAndLatencyMap.put("Latency-" + instance.getCommandKey().name(), String.valueOf(operLatency));
+ insTotalTps += tpsOper;
+ insTotalLatency += operLatency;
+ }
+
+ double instanceLatency = (double) (insTotalLatency) / cumulativeTotalCount;
+
+ tpsAndLatencyMap.put("TPS Instance_Level", String.valueOf(insTotalTps));
+ tpsAndLatencyMap.put("Latency Instance_Level", String.valueOf(instanceLatency));
+
+ return tpsAndLatencyMap.toString();
+ }
+ };
+
+ /**
+ * Implementation of request metrics with using servo guage metric type.
+ */
+ protected abstract class GaugeMetric extends AbstractMonitor implements Gauge {
+
+ public GaugeMetric(MonitorConfig config) {
+ super(config.withAdditionalTag(DataSourceType.GAUGE));
+ }
+
+ @Override
+ public Number getValue(int n) {
+ return getValue();
+ }
+
+ @Override
+ public abstract Number getValue();
+ }
+
+ /**
+ * Implementation of queue average metrics with using servo information metric
+ * type.
+ */
+ protected abstract class InformationalMetric extends AbstractMonitor implements Informational {
+ public InformationalMetric(MonitorConfig config) {
+ super(config.withAdditionalTag(DataSourceType.INFORMATIONAL));
+ }
+
+ @Override
+ public String getValue(int n) {
+ return getValue();
+ }
+
+ @Override
+ public abstract String getValue();
+ }
+
+ /**
+ * Get the total requests and failed requests for instance level.
+ *
+ * @param metricsName Name of the metrics
+ * @param instance object of latest metrics
+ * @param fieldName metric field
+ * @param metricToEvaluate observable method to be called for preparation of metrics.
+ * @return Guage metrics
+ */
+ protected Monitor getRequestValuesGaugeMonitor(final String metricsName,
+ final Func0 metricToEvaluate) {
+ return new GaugeMetric(MonitorConfig.builder(metricsName).build()) {
+
+ @Override
+ public Number getValue() {
+ return metricToEvaluate.call();
+ }
+ };
+ }
+
+ /**
+ * Get the total requests and failed requests for each producer.
+ *
+ * @param metricsName Name of the metrics
+ * @param instance object of latest metrics
+ * @param fieldName metric field
+ * @param metricToEvaluate observable method to be called for preparation of metrics.
+ * @return Guage metrics
+ */
+ protected Monitor getInfoMetricsOperationLevel(final String metricsName,
+ final Func0 metricToEvaluate) {
+ return new InformationalMetric(MonitorConfig.builder(metricsName).build()) {
+ @Override
+ public String getValue() {
+ return metricToEvaluate.call();
+ }
+ };
+ }
+
+ /**
+ * Get the total requests and failed requests for each producer.
+ *
+ * @param metricsName Name of the metrics
+ * @param instance object of latest metrics
+ * @param fieldName metric field
+ * @param metricToEvaluate observable method to be called for preparation of metrics.
+ * @return Guage metrics
+ */
+ protected Monitor getInfoMetricsOperationalAndInstance(final String name,
+ final Func0 metricToEvaluate) {
+ return new InformationalMetric(MonitorConfig.builder(name).build()) {
+ @Override
+ public String getValue() {
+ return metricToEvaluate.call();
+ }
+ };
+ }
+
+ /**
+ * Prepare the initial metrics.
+ *
+ * @return List of monitors
+ */
+ private List> getMetricsMonitors() {
+
+ List> monitors = new ArrayList>();
+ monitors.add(getRequestValuesGaugeMonitor("TotalRequestsPerProvider INSTANCE_LEVEL",
+ getTotalReqProvider));
+
+ monitors.add(getRequestValuesGaugeMonitor("TotalFailedRequestsPerProvider INSTANCE_LEVEL",
+ getTotalFailedReqProvider));
+
+ monitors.add(getRequestValuesGaugeMonitor("TotalRequestsPerConsumer INSTANCE_LEVEL",
+ getTotalReqConsumer));
+
+ monitors.add(getRequestValuesGaugeMonitor("TotalFailRequestsPerConsumer INSTANCE_LEVEL",
+ getFailedTotalReqConsumer));
+
+ monitors.add(getInfoMetricsOperationLevel("TotalRequestProvider OPERATIONAL_LEVEL",
+ getTotalReqProdOperLevel));
+
+ monitors.add(getInfoMetricsOperationLevel("TotalFailedRequestProvider OPERATIONAL_LEVEL",
+ getTotalReqFailProdOperLevel));
+
+ monitors.add(getInfoMetricsOperationalAndInstance("RequestQueueRelated", getQueueMetrics));
+
+ monitors.add(getInfoMetricsOperationalAndInstance("TPS and Latency", getTpsAndLatency));
+
+ monitors.add(getInfoMetricsOperationalAndInstance("CPU and Memory", getCpuAndMemory));
+
+ return monitors;
+ }
+}
diff --git a/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/performance/MetricsDataMonitor.java b/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/performance/MetricsDataMonitor.java
new file mode 100644
index 00000000000..afe7054cc90
--- /dev/null
+++ b/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/performance/MetricsDataMonitor.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.servicecomb.foundation.metrics.performance;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Implements the collection of metrics such as total request, total fail
+ * request and average times for requests.
+ */
+public class MetricsDataMonitor {
+
+ // inc
+ // invocation start
+ // succ + fail
+ public Long totalReqProvider = new Long(0);
+
+ // inc
+ // after invocation finished
+ public Long totalFailReqProvider = new Long(0);
+
+ // inc
+ // after invocation start
+ public Long totalReqConsumer = new Long(0);
+
+ // inc
+ // after invocation finished
+ public Long totalFailReqConsumer = new Long(0);
+
+ // key is operQualifiedName
+ // inc
+ // after invocation finished
+ public Map operMetricsTotalReq = new ConcurrentHashMap();
+
+ // key is operQualifiedName
+ // inc
+ // after invocation finished
+ public Map operMetricsTotalFailReq = new ConcurrentHashMap();
+
+ // key is operQualifiedName
+ public Map queueMetrics = new ConcurrentHashMap();
+
+ /**
+ * default constructor.
+ */
+ public MetricsDataMonitor() {
+
+ }
+
+ /**
+ * Returns the map of average values for both instance and operational level.
+ *
+ * @param pathId Operation path id
+ * @return QueueMetrics object based on key
+ */
+ public QueueMetricsData getOrCreateQueueMetrics(String pathId) {
+ return queueMetrics.computeIfAbsent(pathId, p -> {
+ return new QueueMetricsData();
+ });
+ }
+
+ /**
+ * Returns the map of average values for both instance and operational level.
+ *
+ * @return queue metrics map
+ */
+ public Map getQueueMetrics() {
+ return queueMetrics;
+ }
+
+ /**
+ * Returns the map of average values for both instance and operational level.
+ *
+ * @return queue metrics map
+ */
+ public Map setQueueMetrics(Map newMap) {
+ return queueMetrics = newMap;
+ }
+
+ /**
+ * Sets the map of average values for both instance and operational levels.
+ *
+ * @param pathId Operation path id
+ * @param reqQueue RequestQueue
+ */
+ public void setQueueMetrics(String pathId, QueueMetricsData reqQueue) {
+ this.queueMetrics.put(pathId, reqQueue);
+ }
+
+ /**
+ * Returns the total requests per provider.
+ *
+ * @return long total requests for provider
+ */
+ public long getTotalReqProvider() {
+ return totalReqProvider;
+ }
+
+ /**
+ * Increments the total requests per provider.
+ */
+ public void incrementTotalReqProvider() {
+ this.totalReqProvider++;
+ }
+
+ /**
+ * Sets the total requests per provider.
+ */
+ public void setTotalReqProvider(Long totalReqProvider) {
+ this.totalReqProvider = totalReqProvider;
+ }
+
+ /**
+ * Returns the total fail requests per provider.
+ *
+ * @return long total failed requests for provider
+ */
+ public long getTotalFailReqProvider() {
+ return totalFailReqProvider;
+ }
+
+ /**
+ * Sets the total fail requests per provider.
+ */
+ public void incrementTotalFailReqProvider() {
+ this.totalFailReqProvider++;
+ }
+
+ /**
+ * Sets the total failed requests per provider.
+ */
+ public void setTotalFailReqProvider(Long totalFailedReqProvider) {
+ this.totalFailReqProvider = totalFailedReqProvider;
+ }
+
+ /**
+ * Returns the total requests per consumer.
+ *
+ * @return long total requests for consumer
+ */
+ public long getTotalReqConsumer() {
+ return totalReqConsumer;
+ }
+
+ /**
+ * Sets the total requests per consumer.
+ */
+ public void incrementTotalReqConsumer() {
+ this.totalReqConsumer++;
+ }
+
+ /**
+ * Sets the total failed requests per consumer.
+ */
+ public void setTotalReqConsumer(Long totalReqConsumer) {
+ this.totalReqConsumer = totalReqConsumer;
+ }
+
+ /**
+ * Returns the total fail requests per consumer.
+ *
+ * @return long total failed request for consumer
+ */
+ public long getTotalFailReqConsumer() {
+ return totalFailReqConsumer;
+ }
+
+ /**
+ * Sets the total fail requests per consumer.
+ */
+ public void incrementTotalFailReqConsumer() {
+ this.totalFailReqConsumer++;
+ }
+
+ /**
+ * Sets the total failed requests per consumer.
+ */
+ public void setTotalFailReqConsumer(Long totalFailedReqConsumer) {
+ this.totalFailReqConsumer = totalFailedReqConsumer;
+ }
+
+ /**
+ * Returns total requests per provider for operational level.
+ *
+ * @param key Operation path id
+ * @return long total requests per provider
+ */
+ public Long getOperMetTotalReq(String key) {
+ return operMetricsTotalReq.get(key);
+ }
+
+ /**
+ * Sets total requests per provider for operational level.
+ *
+ * @param key pathId
+ * @param val total requests per provider
+ */
+ public void setOperMetTotalReq(String key, Long val) {
+ this.operMetricsTotalReq.put(key, val);
+ }
+
+ /**
+ * Returns total fail requests per provider for operational level.
+ *
+ * @param key Operation path id
+ * @return long total fail requests per provider
+ */
+ public Long getOperMetTotalFailReq(String key) {
+ return operMetricsTotalFailReq.get(key);
+ }
+
+ /**
+ * Sets total fail requests per provider for operational level.
+ *
+ * @param key Operation path id
+ * @param val total fail requests per provider
+ */
+ public void setOperMetTotalFailReq(String key, Long val) {
+ this.operMetricsTotalFailReq.put(key, val);
+ }
+}
diff --git a/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/performance/MetricsDataMonitorUtil.java b/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/performance/MetricsDataMonitorUtil.java
new file mode 100644
index 00000000000..8f16880d3ba
--- /dev/null
+++ b/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/performance/MetricsDataMonitorUtil.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.servicecomb.foundation.metrics.performance;
+
+import io.servicecomb.core.Invocation;
+import io.servicecomb.foundation.metrics.MetricsServoRegistry;
+import io.servicecomb.swagger.invocation.InvocationType;
+
+/**
+ * Implementation of metric util functions such as preparing average queue times
+ * and total requests/fail for producer and instance level.
+ */
+public final class MetricsDataMonitorUtil {
+
+ /**
+ * Sets the total requests per provider and consumer.
+ * @param invocation invocation of request
+ */
+ public void setAllReqProviderAndConsumer(Invocation invocation) {
+ MetricsDataMonitor metricsRef = MetricsServoRegistry.getOrCreateLocalMetrics();
+ String operPath = invocation.getOperationMeta().getMicroserviceQualifiedName();
+
+ if (InvocationType.CONSUMER.equals(invocation.getInvocationType())) {
+ metricsRef.incrementTotalReqConsumer();
+ } else {
+ metricsRef.incrementTotalReqProvider();
+ // note down metrics for operational level.
+ metricsRef.setOperMetTotalReq(operPath,
+ metricsRef.getOperMetTotalReq(operPath) == null ? 1L : metricsRef.getOperMetTotalReq(operPath) + 1);
+ }
+ }
+
+ /**
+ * Sets the total failed requests per provider and consumer.
+ * @param invocation invocation of request
+ */
+ public void setAllFailReqProviderAndConsumer(Invocation invocation) {
+ MetricsDataMonitor metricsRef = MetricsServoRegistry.getOrCreateLocalMetrics();
+ String operPath = invocation.getOperationMeta().getMicroserviceQualifiedName();
+
+ if (InvocationType.CONSUMER.equals(invocation.getInvocationType())) {
+ metricsRef.incrementTotalFailReqConsumer();
+ } else {
+ metricsRef.incrementTotalFailReqProvider();
+ // note down metrics for operational level.
+ metricsRef.setOperMetTotalReq(operPath,
+ metricsRef.getOperMetTotalReq(operPath) == null ? 1L : metricsRef.getOperMetTotalReq(operPath) + 1);
+ }
+ }
+}
diff --git a/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/performance/QueueMetrics.java b/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/performance/QueueMetrics.java
new file mode 100644
index 00000000000..613fee06e1f
--- /dev/null
+++ b/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/performance/QueueMetrics.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.servicecomb.foundation.metrics.performance;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Used to store invocation specific metrics for queue.
+ */
+public class QueueMetrics {
+
+ private AtomicLong queueStartTime = new AtomicLong();
+
+ private AtomicLong endOperTime = new AtomicLong();
+
+ private AtomicLong queueEndTime = new AtomicLong();
+
+ private String operQualifiedName;
+
+ /**
+ * Returns the time when it enters the queue.
+ * @return long
+ */
+ public long getQueueStartTime() {
+ return queueStartTime.get();
+ }
+
+ /**
+ * Sets the time when it enters the queue.
+ * @param startTime Entering time in queue
+ */
+ public void setQueueStartTime(long startTime) {
+ this.queueStartTime.set(startTime);
+ }
+
+ /**
+ * Returns the time when the operation ends.
+ * @return long
+ */
+ public long getEndOperTime() {
+ return endOperTime.get();
+ }
+
+ /**
+ * Sets the time when the operation ends.
+ * @param stopOperTime Start time of operation
+ */
+ public void setEndOperTime(long stopOperTime) {
+ this.endOperTime.set(stopOperTime);
+ }
+
+ /**
+ * Returns the time when it leaves the queue.
+ * @return long
+ */
+ public long getQueueEndTime() {
+ return queueEndTime.get();
+ }
+
+ /**
+ * Sets the time when it leaves the queue.
+ * @param endTime Leaving time from queue
+ */
+ public void setQueueEndTime(long endTime) {
+ this.queueEndTime.set(endTime);
+ }
+
+ /**
+ * Get the microservice qualified name.
+ * @return microservice qualified name
+ */
+ public String getOperQualifiedName() {
+ return operQualifiedName;
+ }
+
+ /**
+ * Set the microservice qualified name.
+ * @param operQualifiedName microservice qualified name
+ */
+ public void setOperQualifiedName(String operQualifiedName) {
+ this.operQualifiedName = operQualifiedName;
+ }
+}
diff --git a/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/performance/QueueMetricsData.java b/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/performance/QueueMetricsData.java
new file mode 100644
index 00000000000..81a536afc47
--- /dev/null
+++ b/foundations/foundation-metrics/src/main/java/io/servicecomb/foundation/metrics/performance/QueueMetricsData.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.servicecomb.foundation.metrics.performance;
+
+/**
+ * Used for holding the request queue related timings like start time, operation time and end time.
+ */
+public class QueueMetricsData {
+
+ // after invocation polled from queue
+ private Long totalTime = new Long(0);
+
+ // succ and fail
+ // after invocation polled from queue
+ private Long totalCount = new Long(0);
+
+ // after invocation finished
+ private Long totalServExecutionTime = new Long(0);
+
+ // after invocation finished
+ private Long totalServExecutionCount = new Long(0);
+
+ // inc and dec
+ // addToQueue inc
+ // pollFromQueue inc
+ // pollFromQueue - addToQueue = countInQueue
+ // after invocation polled from queue
+ private Long countInQueue = new Long(0);
+
+ // after invocation polled from queue
+ private Long minLifeTimeInQueue = new Long(0);
+
+ // after invocation polled from queue
+ private Long maxLifeTimeInQueue = new Long(0);
+
+ /**
+ * Sets total count in queue.
+ */
+ public void incrementCountInQueue() {
+ this.countInQueue++;
+ }
+
+ /**
+ * Deletes total count in queue.
+ */
+ public void decrementCountInQueue() {
+ this.countInQueue--;
+ }
+
+ /**
+ * default constructor.
+ */
+ public QueueMetricsData() {
+
+ }
+
+ /**
+ * Returns the count for calculating average count value in queue.
+ * @return Long
+ */
+ public Long getTotalTime() {
+ return totalTime;
+ }
+
+ /**
+ * Sets the total time for calculating average time in queue.
+ * @param totalTime total time value
+ */
+ public void setTotalTime(long totalTime) {
+ this.totalTime = totalTime;
+ }
+
+ /**
+ * Returns the total count for calculating average count value in queue.
+ * @return Long
+ */
+ public Long getTotalCount() {
+ return totalCount;
+ }
+
+ /**
+ * Sets the total count for calculating average count value in queue.
+ */
+ public void incrementTotalCount() {
+ this.totalCount++;
+ }
+
+ /**
+ * Sets the total count for calculating average count value in queue.
+ * @param totalCount total count
+ */
+ public void setTotalCount(long totalCount) {
+ this.totalCount = totalCount;
+ }
+
+ /**
+ * Returns the count for calculating average value of working time after queue.
+ * @return Long
+ */
+ public Long getTotalServExecutionTime() {
+ return totalServExecutionTime;
+ }
+
+ /**
+ * Sets the count for calculating average value of working time after queue.
+ * @param totalCountAfterQueue count value
+ */
+ public void setTotalServExecutionTime(long totalCountAfterQueue) {
+ this.totalServExecutionTime = totalCountAfterQueue;
+ }
+
+ /**
+ * Returns the total count for calculating average value of working time after queue.
+ * @return Long
+ */
+ public Long getTotalServExecutionCount() {
+ return totalServExecutionCount;
+ }
+
+ /**
+ * Sets the total count for calculating average value of working time after queue.
+ */
+ public void incrementTotalServExecutionCount() {
+ this.totalServExecutionCount++;
+ }
+
+ /**
+ * Sets the total count for calculating average value of working time after queue.
+ * @param totalServExecutionCount total service execution time count
+ */
+ public void setTotalServExecutionCount(long totalServExecutionCount) {
+ this.totalServExecutionCount = totalServExecutionCount;
+ }
+
+ /**
+ * Returns total count in queue.
+ * @return Long
+ */
+ public Long getCountInQueue() {
+ return countInQueue;
+ }
+
+ /**
+ * Returns total count in queue.
+ * @param countInQueue queue count
+ */
+ public void setCountInQueue(long countInQueue) {
+ this.countInQueue = countInQueue;
+ }
+
+ /**
+ * Returns the minimum lifetime in queue.
+ * @return Long
+ */
+ public Long getMinLifeTimeInQueue() {
+ return minLifeTimeInQueue;
+ }
+
+ /**
+ * Sets the minimum lifetime in queue.
+ * @param minLifeTimeInQueue minimum lifetime
+ */
+ public void setMinLifeTimeInQueue(long minLifeTimeInQueue) {
+ if ((this.minLifeTimeInQueue <= 0) || (minLifeTimeInQueue < this.minLifeTimeInQueue)) {
+ this.minLifeTimeInQueue = minLifeTimeInQueue;
+ }
+ }
+
+ /**
+ * Returns maximum lifetime in queue.
+ * @return Long
+ */
+ public Long getMaxLifeTimeInQueue() {
+ return maxLifeTimeInQueue;
+ }
+
+ /**
+ * Sets maximum lifetime in queue.
+ * @param maxLifeTimeInQueue maximum lifetime
+ */
+ public void setMaxLifeTimeInQueue(long maxLifeTimeInQueue) {
+ if ((this.maxLifeTimeInQueue <= 0) || (maxLifeTimeInQueue > this.maxLifeTimeInQueue)) {
+ this.maxLifeTimeInQueue = maxLifeTimeInQueue;
+ }
+ }
+
+ /**
+ * Sets minimum lifetime in queue.
+ * @param maxLifeTimeInQueue maximum lifetime
+ */
+ public void resetMinLifeTimeInQueue() {
+ this.minLifeTimeInQueue = 0L;
+ }
+
+ /**
+ * resets maximum lifetime in queue.
+ * @param maxLifeTimeInQueue maximum lifetime
+ */
+ public void resetMaxLifeTimeInQueue() {
+ this.maxLifeTimeInQueue = 0L;
+ }
+}
diff --git a/foundations/foundation-metrics/src/main/resources/META-INF/spring/metrics.bean.xml b/foundations/foundation-metrics/src/main/resources/META-INF/spring/metrics.bean.xml
index 49b330acffa..3e70c7dc696 100644
--- a/foundations/foundation-metrics/src/main/resources/META-INF/spring/metrics.bean.xml
+++ b/foundations/foundation-metrics/src/main/resources/META-INF/spring/metrics.bean.xml
@@ -24,4 +24,6 @@
+
+
\ No newline at end of file
diff --git a/foundations/foundation-metrics/src/test/java/io/servicecomb/foundation/metrics/TestMetricsServoRegistry.java b/foundations/foundation-metrics/src/test/java/io/servicecomb/foundation/metrics/TestMetricsServoRegistry.java
new file mode 100644
index 00000000000..091722a5982
--- /dev/null
+++ b/foundations/foundation-metrics/src/test/java/io/servicecomb/foundation/metrics/TestMetricsServoRegistry.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.servicecomb.foundation.metrics;
+
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.netflix.servo.publish.PollScheduler;
+
+import io.servicecomb.foundation.metrics.performance.MetricsDataMonitor;
+import io.servicecomb.foundation.metrics.performance.QueueMetricsData;
+
+public class TestMetricsServoRegistry {
+ MetricsDataMonitor metricsDataMonitor = null;
+
+ MetricsDataMonitor localData = null;
+
+ MetricsServoRegistry metricsRegistry = null;
+
+ @Before
+ public void setUp() throws Exception {
+ metricsRegistry = new MetricsServoRegistry();
+ localData = metricsRegistry.getLocalMetrics();
+ metricsDataMonitor = MetricsServoRegistry.getOrCreateLocalMetrics();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ PollScheduler.getInstance().stop();
+ metricsRegistry = null;
+ localData = null;
+ metricsDataMonitor = null;
+ }
+
+ @Test
+ public void testAllRegistryMetrics() throws Exception {
+ metricsDataMonitor.incrementTotalReqProvider();
+ metricsDataMonitor.incrementTotalFailReqProvider();
+ metricsDataMonitor.incrementTotalReqConsumer();
+ metricsDataMonitor.incrementTotalFailReqConsumer();
+ metricsDataMonitor.setOperMetTotalReq("sayHi", 20L);
+ metricsDataMonitor.setOperMetTotalFailReq("sayHi", 20L);
+ localData = metricsRegistry.getLocalMetrics();
+ localData.setOperMetTotalReq("sayHi", 10L);
+ localData.setOperMetTotalFailReq("sayHi", 10L);
+
+ metricsRegistry.afterPropertiesSet();
+ Thread.sleep(1000);
+ // get the metrics from local data and compare
+ localData = metricsRegistry.getLocalMetrics();
+ Assert.assertEquals(1, localData.getTotalReqProvider());
+ Assert.assertEquals(1, localData.getTotalFailReqProvider());
+ Assert.assertEquals(1, localData.getTotalReqConsumer());
+ Assert.assertEquals(1, localData.getTotalFailReqConsumer());
+ Assert.assertEquals(20L, localData.getOperMetTotalReq("sayHi").longValue());
+ Assert.assertEquals(20L, localData.getOperMetTotalFailReq("sayHi").longValue());
+
+ MetricsDataMonitor localData1 = metricsRegistry.getLocalMetrics();
+ Assert.assertEquals(20L, localData1.getOperMetTotalReq("sayHi").longValue());
+ Assert.assertEquals(20L, localData1.getOperMetTotalFailReq("sayHi").longValue());
+ }
+
+ @Test
+ public void testOperationalProviderMetrics() throws Exception {
+ MetricsDataMonitor metricsDataMonitor = MetricsServoRegistry.getOrCreateLocalMetrics();
+ metricsDataMonitor.setOperMetTotalReq("sayHi", 20L);
+ metricsDataMonitor.setOperMetTotalFailReq("sayHi", 20L);
+ localData = metricsRegistry.getLocalMetrics();
+
+ metricsRegistry.afterPropertiesSet();
+ Thread.sleep(1000);
+ // get the metrics from local data and compare
+ localData = metricsRegistry.getLocalMetrics();
+ Assert.assertEquals(1, localData.getTotalReqProvider());
+ Assert.assertEquals(1, localData.getTotalFailReqProvider());
+ Assert.assertEquals(1, localData.getTotalReqConsumer());
+ Assert.assertEquals(1, localData.getTotalFailReqConsumer());
+ Assert.assertEquals(20L, localData.getOperMetTotalReq("sayHi").longValue());
+ Assert.assertEquals(20L, localData.getOperMetTotalFailReq("sayHi").longValue());
+
+ MetricsDataMonitor localData1 = metricsRegistry.getLocalMetrics();
+ Assert.assertEquals(20L, localData1.getOperMetTotalReq("sayHi").longValue());
+ Assert.assertEquals(20L, localData1.getOperMetTotalFailReq("sayHi").longValue());
+ }
+
+ @Test
+ public void testQueueMetrics() throws Exception {
+ QueueMetricsData reqQueue1 = new QueueMetricsData();
+ reqQueue1.setCountInQueue(1);
+ reqQueue1.setMaxLifeTimeInQueue(2);
+ reqQueue1.setMinLifeTimeInQueue(1);
+ reqQueue1.setTotalCount(10);
+ reqQueue1.setTotalTime(100);
+ reqQueue1.setTotalServExecutionCount(5);
+ reqQueue1.setTotalServExecutionTime(50);
+ metricsDataMonitor.setQueueMetrics("/sayBye", reqQueue1);
+
+ metricsRegistry.afterPropertiesSet();
+ Thread.sleep(1000);
+ // get the metrics from local data and compare
+ Map localMap = localData.getQueueMetrics();
+ QueueMetricsData reqQueue2 = localMap.get("/sayBye");
+
+ Assert.assertEquals(1L, reqQueue2.getCountInQueue().longValue());
+ Assert.assertEquals(1L, reqQueue2.getMinLifeTimeInQueue().longValue());
+ Assert.assertEquals(2L, reqQueue2.getMaxLifeTimeInQueue().longValue());
+ Assert.assertEquals(10L, reqQueue2.getTotalCount().longValue());
+ Assert.assertEquals(100L, reqQueue2.getTotalTime().longValue());
+ Assert.assertEquals(5, reqQueue2.getTotalServExecutionCount().longValue());
+ Assert.assertEquals(50, reqQueue2.getTotalServExecutionTime().longValue());
+ }
+
+ @Test
+ public void testQueueMetrics1() throws Exception {
+ QueueMetricsData reqQueue1 = new QueueMetricsData();
+ reqQueue1.setCountInQueue(10);
+ reqQueue1.setMaxLifeTimeInQueue(2);
+ reqQueue1.setMinLifeTimeInQueue(2);
+ reqQueue1.setTotalCount(1);
+ reqQueue1.setTotalTime(10);
+ reqQueue1.setTotalServExecutionCount(1);
+ reqQueue1.setTotalServExecutionTime(1);
+ localData.setQueueMetrics("/sayBye", reqQueue1);
+
+ QueueMetricsData reqQueue2 = new QueueMetricsData();
+ reqQueue2.setCountInQueue(10);
+ reqQueue2.setMaxLifeTimeInQueue(2);
+ reqQueue2.setMinLifeTimeInQueue(2);
+ reqQueue2.setTotalCount(10);
+ reqQueue2.setTotalTime(100);
+ reqQueue2.setTotalServExecutionCount(5);
+ reqQueue2.setTotalServExecutionTime(50);
+ metricsDataMonitor.setQueueMetrics("/sayBye", reqQueue2);
+
+ metricsRegistry.afterPropertiesSet();
+ Thread.sleep(1000);
+ // get the metrics from local data and compare
+ Map localMap = localData.getQueueMetrics();
+ QueueMetricsData reqQueue3 = localMap.get("/sayBye");
+
+ Assert.assertEquals(10L, reqQueue3.getCountInQueue().longValue());
+ Assert.assertEquals(2L, reqQueue3.getMinLifeTimeInQueue().longValue());
+ Assert.assertEquals(2L, reqQueue3.getMaxLifeTimeInQueue().longValue());
+ Assert.assertEquals(10L, reqQueue3.getTotalCount().longValue());
+ Assert.assertEquals(100L, reqQueue3.getTotalTime().longValue());
+ Assert.assertEquals(5L, reqQueue3.getTotalServExecutionCount().longValue());
+ Assert.assertEquals(50L, reqQueue3.getTotalServExecutionTime().longValue());
+
+ }
+}
diff --git a/foundations/foundation-metrics/src/test/java/io/servicecomb/foundation/metrics/performance/TestMetricsDataMonitor.java b/foundations/foundation-metrics/src/test/java/io/servicecomb/foundation/metrics/performance/TestMetricsDataMonitor.java
new file mode 100644
index 00000000000..2ef056bd35e
--- /dev/null
+++ b/foundations/foundation-metrics/src/test/java/io/servicecomb/foundation/metrics/performance/TestMetricsDataMonitor.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.servicecomb.foundation.metrics.performance;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestMetricsDataMonitor {
+ MetricsDataMonitor metricsDataMonitor = null;
+
+ @Before
+ public void setUp() throws Exception {
+ metricsDataMonitor = new MetricsDataMonitor();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ metricsDataMonitor = null;
+ }
+
+ @Test
+ public void testReqMapValues() {
+ QueueMetricsData reqQueue = new QueueMetricsData();
+ reqQueue.setCountInQueue(1L);
+ reqQueue.setMaxLifeTimeInQueue(5L);
+ reqQueue.setMinLifeTimeInQueue(1L);
+ reqQueue.toString();
+
+ metricsDataMonitor.setQueueMetrics("/sayHi", reqQueue);
+ QueueMetricsData reqQueueTest = metricsDataMonitor.getOrCreateQueueMetrics("/sayHi");
+ QueueMetricsData reqQueueTestAbsent = metricsDataMonitor.getOrCreateQueueMetrics("");
+ Assert.assertEquals(1, reqQueueTest.getCountInQueue().longValue());
+ Assert.assertEquals(5, reqQueueTest.getMaxLifeTimeInQueue().longValue());
+ Assert.assertEquals(1, reqQueueTest.getMinLifeTimeInQueue().longValue());
+ Assert.assertEquals(0, reqQueueTestAbsent.getCountInQueue().longValue());
+ }
+
+ @Test
+ public void testOperationMetricsMap() {
+ QueueMetrics reqQueue = new QueueMetrics();
+ QueueMetricsData queueMetrics = new QueueMetricsData();
+ queueMetrics.incrementCountInQueue();
+ reqQueue.setQueueStartTime(200);
+ reqQueue.setEndOperTime(250);
+ reqQueue.setQueueEndTime(300);
+ reqQueue.setOperQualifiedName("name");
+ queueMetrics.setTotalTime(100L);
+ queueMetrics.setTotalServExecutionTime(200L);
+ queueMetrics.setTotalCount(100L);
+ queueMetrics.setTotalServExecutionCount(200L);
+
+ // increment the count to 5.
+ queueMetrics.incrementTotalCount();
+ queueMetrics.incrementTotalCount();
+ queueMetrics.incrementTotalCount();
+ queueMetrics.incrementTotalCount();
+ queueMetrics.incrementTotalCount();
+ queueMetrics.incrementTotalServExecutionCount();
+ queueMetrics.incrementTotalServExecutionCount();
+ queueMetrics.incrementTotalServExecutionCount();
+ queueMetrics.incrementTotalServExecutionCount();
+ queueMetrics.incrementTotalServExecutionCount();
+
+ queueMetrics.setMinLifeTimeInQueue(1);
+ queueMetrics.resetMinLifeTimeInQueue();
+ Assert.assertEquals(0, queueMetrics.getMinLifeTimeInQueue().longValue());
+
+ queueMetrics.setMaxLifeTimeInQueue(1);
+ queueMetrics.resetMaxLifeTimeInQueue();
+ Assert.assertEquals(0, queueMetrics.getMaxLifeTimeInQueue().longValue());
+
+ metricsDataMonitor.setQueueMetrics("/sayHi", queueMetrics);
+
+ //Assert.assertEquals(1, reqQueueTest.getConuntInQueue());
+ Assert.assertEquals(300, reqQueue.getQueueEndTime());
+ Assert.assertEquals(250, reqQueue.getEndOperTime());
+ Assert.assertEquals(200, reqQueue.getQueueStartTime());
+ Assert.assertEquals("name", reqQueue.getOperQualifiedName());
+ Assert.assertEquals(100L, queueMetrics.getTotalTime().longValue());
+ Assert.assertEquals(105L, queueMetrics.getTotalCount().longValue());
+ Assert.assertEquals(200, queueMetrics.getTotalServExecutionTime().longValue());
+ Assert.assertEquals(205L, queueMetrics.getTotalServExecutionCount().longValue());
+ queueMetrics.decrementCountInQueue();
+ Assert.assertEquals(0, queueMetrics.getCountInQueue().longValue());
+ }
+
+ @Test
+ public void testHystrixAvgTimes() {
+
+ // total request for provider
+ metricsDataMonitor.incrementTotalReqProvider();
+ metricsDataMonitor.incrementTotalFailReqProvider();
+ Assert.assertEquals(1, metricsDataMonitor.getTotalReqProvider());
+ Assert.assertEquals(1, metricsDataMonitor.getTotalFailReqProvider());
+ metricsDataMonitor.incrementTotalReqProvider();
+ metricsDataMonitor.incrementTotalFailReqProvider();
+ Assert.assertEquals(2, metricsDataMonitor.getTotalReqProvider());
+ Assert.assertEquals(2, metricsDataMonitor.getTotalFailReqProvider());
+
+ // total request for consumer
+ metricsDataMonitor.incrementTotalReqConsumer();
+ metricsDataMonitor.incrementTotalFailReqConsumer();
+ Assert.assertEquals(1, metricsDataMonitor.getTotalReqConsumer());
+ Assert.assertEquals(1, metricsDataMonitor.getTotalFailReqConsumer());
+ metricsDataMonitor.incrementTotalReqConsumer();
+ metricsDataMonitor.incrementTotalFailReqConsumer();
+ Assert.assertEquals(2, metricsDataMonitor.getTotalReqConsumer());
+ Assert.assertEquals(2, metricsDataMonitor.getTotalFailReqConsumer());
+
+ metricsDataMonitor.setOperMetTotalReq("/sayHi", 10L);
+ metricsDataMonitor.setOperMetTotalFailReq("/sayHi", 20L);
+ Assert.assertEquals(10L, metricsDataMonitor.getOperMetTotalReq("/sayHi").longValue());
+ Assert.assertEquals(20L, metricsDataMonitor.getOperMetTotalFailReq("/sayHi").longValue());
+ }
+}
diff --git a/foundations/foundation-metrics/src/test/java/io/servicecomb/foundation/metrics/performance/TestMetricsDataMonitorUtil.java b/foundations/foundation-metrics/src/test/java/io/servicecomb/foundation/metrics/performance/TestMetricsDataMonitorUtil.java
new file mode 100644
index 00000000000..e739194a57f
--- /dev/null
+++ b/foundations/foundation-metrics/src/test/java/io/servicecomb/foundation/metrics/performance/TestMetricsDataMonitorUtil.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2017 Huawei Technologies Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.servicecomb.foundation.metrics.performance;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.servicecomb.core.Invocation;
+import io.servicecomb.core.definition.OperationMeta;
+import io.servicecomb.foundation.metrics.MetricsServoRegistry;
+import io.servicecomb.swagger.invocation.InvocationType;
+
+public class TestMetricsDataMonitorUtil {
+ MetricsDataMonitor metricsDataMonitor = null;
+
+ MetricsDataMonitorUtil metricsDataMonitorUtil = null;
+
+ @Before
+ public void setUp() throws Exception {
+ metricsDataMonitor = MetricsServoRegistry.getOrCreateLocalMetrics();
+ metricsDataMonitorUtil = new MetricsDataMonitorUtil();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ metricsDataMonitor = null;
+ }
+
+ @Test
+ public void testAllReqConsumer() {
+
+ Invocation invocation = Mockito.mock(Invocation.class);
+ OperationMeta operationMetaData = Mockito.mock(OperationMeta.class);
+ Mockito.when(invocation.getOperationMeta()).thenReturn(operationMetaData);
+ Mockito.when(operationMetaData.getMicroserviceQualifiedName()).thenReturn("/sayHi");
+ Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("/sayHi");
+ Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.CONSUMER);
+
+ metricsDataMonitorUtil.setAllReqProviderAndConsumer(invocation);
+ Assert.assertNotEquals(0L, metricsDataMonitor.getTotalReqConsumer());
+ metricsDataMonitorUtil.setAllFailReqProviderAndConsumer(invocation);
+ Assert.assertNotEquals(0L, metricsDataMonitor.getTotalFailReqConsumer());
+ }
+
+ @Test
+ public void testAllReqProvider() {
+
+ Invocation invocation = Mockito.mock(Invocation.class);
+ OperationMeta operationMetaData = Mockito.mock(OperationMeta.class);
+ Mockito.when(invocation.getOperationMeta()).thenReturn(operationMetaData);
+ Mockito.when(operationMetaData.getMicroserviceQualifiedName()).thenReturn("/sayBye");
+ Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("sayBye");
+ Mockito.when(invocation.getInvocationType()).thenReturn(InvocationType.PRODUCER);
+
+ metricsDataMonitorUtil.setAllReqProviderAndConsumer(invocation);
+ Assert.assertNotEquals(0L, metricsDataMonitor.getTotalReqProvider());
+ metricsDataMonitorUtil.setAllReqProviderAndConsumer(invocation);
+ Assert.assertNotEquals(0L, metricsDataMonitor.getTotalReqProvider());
+ metricsDataMonitorUtil.setAllFailReqProviderAndConsumer(invocation);
+ Assert.assertNotEquals(0L, metricsDataMonitor.getTotalFailReqProvider());
+ metricsDataMonitorUtil.setAllFailReqProviderAndConsumer(invocation);
+ Assert.assertNotEquals(0L, metricsDataMonitor.getTotalFailReqProvider());
+ }
+}
diff --git a/handlers/handler-bizkeeper/pom.xml b/handlers/handler-bizkeeper/pom.xml
index f7d09b8844e..e471a06677f 100644
--- a/handlers/handler-bizkeeper/pom.xml
+++ b/handlers/handler-bizkeeper/pom.xml
@@ -50,7 +50,11 @@
log4j
test
-
+
+ io.servicecomb
+ foundation-metrics
+
+
diff --git a/handlers/handler-bizkeeper/src/main/java/io/servicecomb/bizkeeper/BizkeeperHandler.java b/handlers/handler-bizkeeper/src/main/java/io/servicecomb/bizkeeper/BizkeeperHandler.java
index 7d532922e4a..4ab9f005389 100644
--- a/handlers/handler-bizkeeper/src/main/java/io/servicecomb/bizkeeper/BizkeeperHandler.java
+++ b/handlers/handler-bizkeeper/src/main/java/io/servicecomb/bizkeeper/BizkeeperHandler.java
@@ -28,6 +28,7 @@
import io.servicecomb.core.Handler;
import io.servicecomb.core.Invocation;
+import io.servicecomb.foundation.metrics.performance.MetricsDataMonitorUtil;
import io.servicecomb.swagger.invocation.AsyncResponse;
import io.servicecomb.swagger.invocation.Response;
import rx.Observable;
@@ -78,12 +79,17 @@ public BizkeeperHandler(String groupname) {
public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception {
HystrixObservable command = delegate.createBizkeeperCommand(invocation);
+ //Notedown all request for provider and consumer.
+ new MetricsDataMonitorUtil().setAllReqProviderAndConsumer(invocation);
+
Observable observable = command.toObservable();
observable.subscribe(response -> {
asyncResp.complete(response);
}, error -> {
LOG.warn("catch error in bizkeeper:" + error.getMessage());
asyncResp.fail(invocation.getInvocationType(), error);
+ //Notedown all failed request for provider and consumer.
+ new MetricsDataMonitorUtil().setAllFailReqProviderAndConsumer(invocation);
}, () -> {
});
diff --git a/transports/transport-highway/pom.xml b/transports/transport-highway/pom.xml
index be62c65c4b4..7c10563b720 100644
--- a/transports/transport-highway/pom.xml
+++ b/transports/transport-highway/pom.xml
@@ -46,5 +46,9 @@
log4j
test
+
+ io.servicecomb
+ foundation-metrics
+
diff --git a/transports/transport-highway/src/main/java/io/servicecomb/transport/highway/HighwayServerInvoke.java b/transports/transport-highway/src/main/java/io/servicecomb/transport/highway/HighwayServerInvoke.java
index 405b22acc88..836d87c54db 100644
--- a/transports/transport-highway/src/main/java/io/servicecomb/transport/highway/HighwayServerInvoke.java
+++ b/transports/transport-highway/src/main/java/io/servicecomb/transport/highway/HighwayServerInvoke.java
@@ -32,6 +32,9 @@
import io.servicecomb.core.definition.MicroserviceMetaManager;
import io.servicecomb.core.definition.OperationMeta;
import io.servicecomb.core.definition.SchemaMeta;
+import io.servicecomb.foundation.metrics.MetricsServoRegistry;
+import io.servicecomb.foundation.metrics.performance.QueueMetrics;
+import io.servicecomb.foundation.metrics.performance.QueueMetricsData;
import io.servicecomb.foundation.vertx.tcp.TcpConnection;
import io.servicecomb.swagger.invocation.Response;
import io.servicecomb.swagger.invocation.exception.InvocationException;
@@ -103,9 +106,9 @@ private void doInit(TcpConnection connection, long msgId, RequestHeader header,
this.bodyBuffer = bodyBuffer;
}
- private void runInExecutor() {
+ private void runInExecutor(QueueMetrics metricsData) {
try {
- doRunInExecutor();
+ doRunInExecutor(metricsData);
} catch (Throwable e) {
String msg = String.format("handle request error, %s, msgId=%d",
operationMeta.getMicroserviceQualifiedName(),
@@ -116,11 +119,13 @@ private void runInExecutor() {
}
}
- private void doRunInExecutor() throws Exception {
+ private void doRunInExecutor(QueueMetrics metricsData) throws Exception {
Invocation invocation = HighwayCodec.decodeRequest(header, operationProtobuf, bodyBuffer, protobufFeature);
invocation.getHandlerContext().put(Const.REMOTE_ADDRESS, this.connection.getNetSocket().remoteAddress());
+ updateMetrics(invocation);
invocation.next(response -> {
sendResponse(invocation.getContext(), response);
+ endMetrics(invocation);
});
}
@@ -149,7 +154,59 @@ private void sendResponse(Map context, Response response) {
}
}
+ /**
+ * start time in queue.
+ */
public void execute() {
- operationMeta.getExecutor().execute(this::runInExecutor);
+ QueueMetrics metricsData = initMetrics(operationMeta);
+ operationMeta.getExecutor().execute(() -> runInExecutor(metricsData));
+ }
+
+ /**
+ * Init the metrics. Note down the queue count and start time.
+ * @param operationMeta Operation data
+ * @return QueueMetrics
+ */
+ private QueueMetrics initMetrics(OperationMeta operationMeta) {
+ QueueMetrics metricsData = new QueueMetrics();
+ metricsData.setQueueStartTime(System.currentTimeMillis());
+ metricsData.setOperQualifiedName(operationMeta.getMicroserviceQualifiedName());
+ QueueMetricsData reqQueue = MetricsServoRegistry.getOrCreateLocalMetrics()
+ .getOrCreateQueueMetrics(operationMeta.getMicroserviceQualifiedName());
+ reqQueue.incrementCountInQueue();
+ return metricsData;
+ }
+
+ /**
+ * Update the queue metrics.
+ */
+ private void updateMetrics(Invocation invocation) {
+ QueueMetrics metricsData = (QueueMetrics) invocation.getMetricsData();
+ if (null != metricsData) {
+ metricsData.setQueueEndTime(System.currentTimeMillis());
+ QueueMetricsData reqQueue = MetricsServoRegistry.getOrCreateLocalMetrics()
+ .getOrCreateQueueMetrics(operationMeta.getMicroserviceQualifiedName());
+ reqQueue.incrementTotalCount();
+ Long timeInQueue = metricsData.getQueueEndTime() - metricsData.getQueueStartTime();
+ reqQueue.setTotalTime(reqQueue.getTotalTime() + timeInQueue);
+ reqQueue.setMinLifeTimeInQueue(timeInQueue);
+ reqQueue.setMaxLifeTimeInQueue(timeInQueue);
+ reqQueue.decrementCountInQueue();
+ }
+ }
+
+ /**
+ * Prepare the end time of queue metrics.
+ */
+ private void endMetrics(Invocation invocation) {
+ QueueMetrics metricsData = (QueueMetrics) invocation.getMetricsData();
+ if (null != metricsData) {
+ metricsData.setEndOperTime(System.currentTimeMillis());
+ QueueMetricsData reqQueue = MetricsServoRegistry.getOrCreateLocalMetrics()
+ .getOrCreateQueueMetrics(operationMeta.getMicroserviceQualifiedName());
+ reqQueue.incrementTotalServExecutionCount();
+ reqQueue.setTotalServExecutionTime(
+ reqQueue.getTotalServExecutionTime() + (metricsData.getEndOperTime() - metricsData.getQueueEndTime()));
+ }
}
}
diff --git a/transports/transport-highway/src/test/java/io/servicecomb/transport/highway/TestHighwayServerInvoke.java b/transports/transport-highway/src/test/java/io/servicecomb/transport/highway/TestHighwayServerInvoke.java
index 5e4c68252fa..7f83739bd1d 100644
--- a/transports/transport-highway/src/test/java/io/servicecomb/transport/highway/TestHighwayServerInvoke.java
+++ b/transports/transport-highway/src/test/java/io/servicecomb/transport/highway/TestHighwayServerInvoke.java
@@ -107,11 +107,6 @@ public void test() {
requestHeader.setOperationName(operationMeta.getOperationId());
Assert.assertTrue(highwayServerInvoke.init(connection, 0, requestHeader, null));
- // exe成功
- netSocketBuffer = null;
- highwayServerInvoke.execute();
- Assert.assertEquals(null, netSocketBuffer);
-
// exe失败
MockUtil.getInstance().decodeRequestSucc = false;
highwayServerInvoke.execute();