This is an automated email from the ASF dual-hosted git repository.

ningjiang pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git

commit bd87a7240eb1eb73d854d689b7776079fc4c33c5
Author: zhengyangyong <[email protected]>
AuthorDate: Wed Jan 17 15:36:37 2018 +0800

    SCB-150 add Status Dimension output level support
    
    Signed-off-by: zhengyangyong <[email protected]>
---
 .../common/rest/AbstractRestInvocation.java        |   2 +-
 .../org/apache/servicecomb/core/Invocation.java    |   4 +-
 .../core/metrics/InvocationFinishedEvent.java      |  11 +-
 .../core/provider/consumer/InvokerUtils.java       |   9 +-
 .../servicecomb/metrics/common/CallMetric.java     |   4 +-
 .../metrics/common/MetricsDimension.java           |  31 ++--
 .../servicecomb/metrics/core/MetricsConfig.java    |   2 +
 .../core/event/DefaultEventListenerManager.java    |  17 ++-
 .../event/InvocationFinishedEventListener.java     |  14 +-
 .../event/dimension/CodeGroupStatusConvertor.java  |  45 ++++++
 .../dimension/CodeStatusConvertor.java}            |   9 +-
 .../dimension/StatusConvertor.java}                |   6 +-
 .../event/dimension/StatusConvertorFactory.java    |  53 +++++++
 .../dimension/SuccessFailedStatusConvertor.java}   |  12 +-
 .../metrics/core/monitor/CallMonitor.java          |  90 ++++++------
 .../core/monitor/ConsumerInvocationMonitor.java    |   3 +-
 .../core/monitor/ProducerInvocationMonitor.java    |   3 +-
 .../metrics/core/TestEventAndRunner.java           |  72 ++++++----
 .../metrics/core/TestStatusDimension.java          | 158 +++++++++++++++++++++
 .../transport/highway/HighwayServerInvoke.java     |   2 +-
 20 files changed, 433 insertions(+), 114 deletions(-)

diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java
index 0ee7999..36c1739 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/AbstractRestInvocation.java
@@ -189,7 +189,7 @@ public abstract class AbstractRestInvocation {
     invocation.next(resp -> {
       sendResponseQuietly(resp);
 
-      invocation.triggerFinishedEvent(resp.isSuccessed());
+      invocation.triggerFinishedEvent(resp.getStatusCode(), 
resp.isSuccessed());
       endMetrics();
     });
   }
diff --git a/core/src/main/java/org/apache/servicecomb/core/Invocation.java 
b/core/src/main/java/org/apache/servicecomb/core/Invocation.java
index 19241b8..81f25f8 100644
--- a/core/src/main/java/org/apache/servicecomb/core/Invocation.java
+++ b/core/src/main/java/org/apache/servicecomb/core/Invocation.java
@@ -202,12 +202,12 @@ public class Invocation extends SwaggerInvocation {
         operationMeta.getMicroserviceQualifiedName(), this.invocationType, 
startProcessingTime - startTime));
   }
 
-  public void triggerFinishedEvent(boolean success) {
+  public void triggerFinishedEvent(int statusCode, boolean success) {
     long finishedTime = System.nanoTime();
     EventUtils
         .triggerEvent(new 
InvocationFinishedEvent(operationMeta.getMicroserviceQualifiedName(),
             this.invocationType, finishedTime - startProcessingTime,
-            finishedTime - startTime, success));
+            finishedTime - startTime, statusCode, success));
   }
 
   public boolean isSync() {
diff --git 
a/core/src/main/java/org/apache/servicecomb/core/metrics/InvocationFinishedEvent.java
 
b/core/src/main/java/org/apache/servicecomb/core/metrics/InvocationFinishedEvent.java
index ea54d67..4de6154 100644
--- 
a/core/src/main/java/org/apache/servicecomb/core/metrics/InvocationFinishedEvent.java
+++ 
b/core/src/main/java/org/apache/servicecomb/core/metrics/InvocationFinishedEvent.java
@@ -29,6 +29,8 @@ public class InvocationFinishedEvent implements Event {
 
   private final long totalElapsedNanoTime;
 
+  private final int statusCode;
+
   private final boolean success;
 
   public String getOperationName() {
@@ -47,18 +49,21 @@ public class InvocationFinishedEvent implements Event {
     return totalElapsedNanoTime;
   }
 
+  public int getStatusCode() {
+    return statusCode;
+  }
+
   public boolean isSuccess() {
     return success;
   }
 
   public InvocationFinishedEvent(String operationName, InvocationType 
invocationType,
-      long processElapsedNanoTime,
-      long totalElapsedNanoTime,
-      boolean success) {
+      long processElapsedNanoTime, long totalElapsedNanoTime, int statusCode, 
boolean success) {
     this.operationName = operationName;
     this.invocationType = invocationType;
     this.processElapsedNanoTime = processElapsedNanoTime;
     this.totalElapsedNanoTime = totalElapsedNanoTime;
+    this.statusCode = statusCode;
     this.success = success;
   }
 }
diff --git 
a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/InvokerUtils.java
 
b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/InvokerUtils.java
index e8b8247..2635ac3 100644
--- 
a/core/src/main/java/org/apache/servicecomb/core/provider/consumer/InvokerUtils.java
+++ 
b/core/src/main/java/org/apache/servicecomb/core/provider/consumer/InvokerUtils.java
@@ -63,6 +63,7 @@ public final class InvokerUtils {
 
   public static Response innerSyncInvoke(Invocation invocation) {
     boolean success = false;
+    int statusCode = 0;
     try {
       triggerStartedEvent(invocation);
       SyncResponseExecutor respExecutor = new SyncResponseExecutor();
@@ -72,6 +73,7 @@ public final class InvokerUtils {
 
       Response response = respExecutor.waitResponse();
       success = response.isSuccessed();
+      statusCode = response.getStatusCode();
       return response;
     } catch (Throwable e) {
       String msg =
@@ -79,7 +81,7 @@ public final class InvokerUtils {
       LOGGER.debug(msg, e);
       return Response.createConsumerFail(e);
     } finally {
-      invocation.triggerFinishedEvent(success);
+      invocation.triggerFinishedEvent(statusCode, success);
     }
   }
 
@@ -92,11 +94,12 @@ public final class InvokerUtils {
       invocation.setResponseExecutor(respExecutor);
 
       invocation.next(ar -> {
-        invocation.triggerFinishedEvent(ar.isSuccessed());
+        invocation.triggerFinishedEvent(ar.getStatusCode(), ar.isSuccessed());
         asyncResp.handle(ar);
       });
     } catch (Throwable e) {
-      invocation.triggerFinishedEvent(false);
+      //if throw exception,we can use 500 for status code ?
+      invocation.triggerFinishedEvent(500, false);
       LOGGER.error("invoke failed, {}", 
invocation.getOperationMeta().getMicroserviceQualifiedName());
       asyncResp.consumerFail(e);
     }
diff --git 
a/metrics/metrics-common/src/main/java/org/apache/servicecomb/metrics/common/CallMetric.java
 
b/metrics/metrics-common/src/main/java/org/apache/servicecomb/metrics/common/CallMetric.java
index 56d0f99..4c5c862 100644
--- 
a/metrics/metrics-common/src/main/java/org/apache/servicecomb/metrics/common/CallMetric.java
+++ 
b/metrics/metrics-common/src/main/java/org/apache/servicecomb/metrics/common/CallMetric.java
@@ -45,7 +45,7 @@ public class CallMetric {
         return value;
       }
     }
-    return null;
+    return new LongMetricValue(dimensionValue, 0L, null);
   }
 
   public List<DoubleMetricValue> getTpsValues() {
@@ -58,7 +58,7 @@ public class CallMetric {
         return value;
       }
     }
-    return null;
+    return new DoubleMetricValue(dimensionValue, 0.0, null);
   }
 
   public CallMetric(String prefix) {
diff --git 
a/metrics/metrics-common/src/main/java/org/apache/servicecomb/metrics/common/MetricsDimension.java
 
b/metrics/metrics-common/src/main/java/org/apache/servicecomb/metrics/common/MetricsDimension.java
index 23f1f40..904cc25 100644
--- 
a/metrics/metrics-common/src/main/java/org/apache/servicecomb/metrics/common/MetricsDimension.java
+++ 
b/metrics/metrics-common/src/main/java/org/apache/servicecomb/metrics/common/MetricsDimension.java
@@ -17,23 +17,30 @@
 
 package org.apache.servicecomb.metrics.common;
 
-import 
org.apache.servicecomb.foundation.common.exceptions.ServiceCombException;
-
 public class MetricsDimension {
   public static final String DIMENSION_STATUS = "Status";
 
   public static final String DIMENSION_STATUS_ALL = "all";
 
-  public static final String DIMENSION_STATUS_SUCCESS = "success";
+  public static final String DIMENSION_STATUS_SUCCESS_FAILED_SUCCESS = 
"success";
+
+  public static final String DIMENSION_STATUS_SUCCESS_FAILED_FAILED = "failed";
+
+  public static final String DIMENSION_STATUS_CODE_GROUP_1XX = "1xx";
+
+  public static final String DIMENSION_STATUS_CODE_GROUP_2XX = "2xx";
+
+  public static final String DIMENSION_STATUS_CODE_GROUP_3XX = "3xx";
+
+  public static final String DIMENSION_STATUS_CODE_GROUP_4XX = "4xx";
+
+  public static final String DIMENSION_STATUS_CODE_GROUP_5XX = "5xx";
+
+  public static final String DIMENSION_STATUS_CODE_GROUP_OTHER = "xxx";
+
+  public static final String DIMENSION_STATUS_OUTPUT_LEVEL_SUCCESS_FAILED = 
"success_failed";
 
-  public static final String DIMENSION_STATUS_FAILED = "failed";
+  public static final String DIMENSION_STATUS_OUTPUT_LEVEL_CODE_GROUP = 
"code_group";
 
-  public static String[] getDimensionOptions(String dimension) {
-    if (DIMENSION_STATUS.equals(dimension)) {
-      return new String[] {MetricsDimension.DIMENSION_STATUS_ALL,
-          MetricsDimension.DIMENSION_STATUS_SUCCESS,
-          MetricsDimension.DIMENSION_STATUS_FAILED};
-    }
-    throw new ServiceCombException("illegal dimension key : " + dimension);
-  }
+  public static final String DIMENSION_STATUS_OUTPUT_LEVEL_CODE = "code";
 }
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsConfig.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsConfig.java
index b903f15..cbf6455 100644
--- 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsConfig.java
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsConfig.java
@@ -19,4 +19,6 @@ package org.apache.servicecomb.metrics.core;
 
 public class MetricsConfig {
   public static final String METRICS_POLLING_TIME = 
"servicecomb.metrics.window_time";
+
+  public static final String METRICS_DIMENSION_STATUS_OUTPUT_LEVEL = 
"servicecomb.metrics.dimension.status.output_level";
 }
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/DefaultEventListenerManager.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/DefaultEventListenerManager.java
index 42aa024..6dc6df4 100644
--- 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/DefaultEventListenerManager.java
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/DefaultEventListenerManager.java
@@ -19,18 +19,31 @@ package org.apache.servicecomb.metrics.core.event;
 
 import org.apache.servicecomb.foundation.common.event.EventListener;
 import org.apache.servicecomb.foundation.common.utils.EventUtils;
+import org.apache.servicecomb.metrics.common.MetricsDimension;
+import org.apache.servicecomb.metrics.core.MetricsConfig;
+import 
org.apache.servicecomb.metrics.core.event.dimension.StatusConvertorFactory;
 import org.apache.servicecomb.metrics.core.monitor.RegistryMonitor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+import com.netflix.config.DynamicPropertyFactory;
+
 @Component
 public class DefaultEventListenerManager implements EventListenerManager {
 
   @Autowired
-  public DefaultEventListenerManager(RegistryMonitor registryMonitor) {
+  public DefaultEventListenerManager(RegistryMonitor registryMonitor, 
StatusConvertorFactory convertorFactory) {
+    this(registryMonitor, convertorFactory, DynamicPropertyFactory
+        
.getInstance().getStringProperty(MetricsConfig.METRICS_DIMENSION_STATUS_OUTPUT_LEVEL,
+            
MetricsDimension.DIMENSION_STATUS_OUTPUT_LEVEL_SUCCESS_FAILED).get());
+  }
+
+  public DefaultEventListenerManager(RegistryMonitor registryMonitor, 
StatusConvertorFactory convertorFactory,
+      String outputLevel) {
     this.registerEventListener(new 
InvocationStartedEventListener(registryMonitor));
     this.registerEventListener(new 
InvocationStartProcessingEventListener(registryMonitor));
-    this.registerEventListener(new 
InvocationFinishedEventListener(registryMonitor));
+    this.registerEventListener(
+        new InvocationFinishedEventListener(registryMonitor, 
convertorFactory.getConvertor(outputLevel)));
   }
 
   @Override
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/InvocationFinishedEventListener.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/InvocationFinishedEventListener.java
index 8d15eac..5b886b6 100644
--- 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/InvocationFinishedEventListener.java
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/InvocationFinishedEventListener.java
@@ -21,17 +21,20 @@ import 
org.apache.servicecomb.core.metrics.InvocationFinishedEvent;
 import org.apache.servicecomb.foundation.common.event.Event;
 import org.apache.servicecomb.foundation.common.event.EventListener;
 import org.apache.servicecomb.metrics.common.MetricsDimension;
+import org.apache.servicecomb.metrics.core.event.dimension.StatusConvertor;
 import org.apache.servicecomb.metrics.core.monitor.ConsumerInvocationMonitor;
 import org.apache.servicecomb.metrics.core.monitor.ProducerInvocationMonitor;
 import org.apache.servicecomb.metrics.core.monitor.RegistryMonitor;
 import org.apache.servicecomb.swagger.invocation.InvocationType;
 
 public class InvocationFinishedEventListener implements EventListener {
-
   private final RegistryMonitor registryMonitor;
 
-  public InvocationFinishedEventListener(RegistryMonitor registryMonitor) {
+  private final StatusConvertor convertor;
+
+  public InvocationFinishedEventListener(RegistryMonitor registryMonitor, 
StatusConvertor convertor) {
     this.registryMonitor = registryMonitor;
+    this.convertor = convertor;
   }
 
   @Override
@@ -42,17 +45,16 @@ public class InvocationFinishedEventListener implements 
EventListener {
   @Override
   public void process(Event data) {
     InvocationFinishedEvent event = (InvocationFinishedEvent) data;
+    String statusDimensionValue = convertor.convert(event.isSuccess(), 
event.getStatusCode());
     if (InvocationType.PRODUCER.equals(event.getInvocationType())) {
       ProducerInvocationMonitor monitor = 
registryMonitor.getProducerInvocationMonitor(event.getOperationName());
       monitor.getExecutionTime().update(event.getProcessElapsedNanoTime());
       monitor.getProducerLatency().update(event.getTotalElapsedNanoTime());
-      monitor.getProducerCall().increment(MetricsDimension.DIMENSION_STATUS,
-          event.isSuccess() ? MetricsDimension.DIMENSION_STATUS_SUCCESS : 
MetricsDimension.DIMENSION_STATUS_FAILED);
+      monitor.getProducerCall().increment(MetricsDimension.DIMENSION_STATUS, 
statusDimensionValue);
     } else {
       ConsumerInvocationMonitor monitor = 
registryMonitor.getConsumerInvocationMonitor(event.getOperationName());
       monitor.getConsumerLatency().update(event.getTotalElapsedNanoTime());
-      monitor.getConsumerCall().increment(MetricsDimension.DIMENSION_STATUS,
-          event.isSuccess() ? MetricsDimension.DIMENSION_STATUS_SUCCESS : 
MetricsDimension.DIMENSION_STATUS_FAILED);
+      monitor.getConsumerCall().increment(MetricsDimension.DIMENSION_STATUS, 
statusDimensionValue);
     }
   }
 }
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/CodeGroupStatusConvertor.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/CodeGroupStatusConvertor.java
new file mode 100644
index 0000000..92b99d0
--- /dev/null
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/CodeGroupStatusConvertor.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.servicecomb.metrics.core.event.dimension;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status.Family;
+
+import org.apache.servicecomb.metrics.common.MetricsDimension;
+
+public class CodeGroupStatusConvertor implements StatusConvertor {
+
+  private final Map<Family, String> families;
+
+  public CodeGroupStatusConvertor() {
+    this.families = new HashMap<>();
+    this.families.put(Family.INFORMATIONAL, 
MetricsDimension.DIMENSION_STATUS_CODE_GROUP_1XX);
+    this.families.put(Family.SUCCESSFUL, 
MetricsDimension.DIMENSION_STATUS_CODE_GROUP_2XX);
+    this.families.put(Family.REDIRECTION, 
MetricsDimension.DIMENSION_STATUS_CODE_GROUP_3XX);
+    this.families.put(Family.CLIENT_ERROR, 
MetricsDimension.DIMENSION_STATUS_CODE_GROUP_4XX);
+    this.families.put(Family.SERVER_ERROR, 
MetricsDimension.DIMENSION_STATUS_CODE_GROUP_5XX);
+    this.families.put(Family.OTHER, 
MetricsDimension.DIMENSION_STATUS_CODE_GROUP_OTHER);
+  }
+
+  @Override
+  public String convert(boolean success, int statusCode) {
+    return families.get(Family.familyOf(statusCode));
+  }
+}
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsConfig.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/CodeStatusConvertor.java
similarity index 77%
copy from 
metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsConfig.java
copy to 
metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/CodeStatusConvertor.java
index b903f15..b01f5da 100644
--- 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsConfig.java
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/CodeStatusConvertor.java
@@ -15,8 +15,11 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.metrics.core;
+package org.apache.servicecomb.metrics.core.event.dimension;
 
-public class MetricsConfig {
-  public static final String METRICS_POLLING_TIME = 
"servicecomb.metrics.window_time";
+public class CodeStatusConvertor implements StatusConvertor {
+  @Override
+  public String convert(boolean success, int statusCode) {
+    return String.valueOf(statusCode);
+  }
 }
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsConfig.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/StatusConvertor.java
similarity index 83%
copy from 
metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsConfig.java
copy to 
metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/StatusConvertor.java
index b903f15..17023b6 100644
--- 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsConfig.java
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/StatusConvertor.java
@@ -15,8 +15,8 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.metrics.core;
+package org.apache.servicecomb.metrics.core.event.dimension;
 
-public class MetricsConfig {
-  public static final String METRICS_POLLING_TIME = 
"servicecomb.metrics.window_time";
+public interface StatusConvertor {
+  String convert(boolean success, int statusCode);
 }
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/StatusConvertorFactory.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/StatusConvertorFactory.java
new file mode 100644
index 0000000..369cda4
--- /dev/null
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/StatusConvertorFactory.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.servicecomb.metrics.core.event.dimension;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.servicecomb.metrics.common.MetricsDimension;
+import org.apache.servicecomb.metrics.core.MetricsConfig;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class StatusConvertorFactory {
+
+  private final Map<String, Supplier<StatusConvertor>> suppliers;
+
+  public StatusConvertorFactory() {
+    this.suppliers = new HashMap<>();
+    this.suppliers.put(MetricsDimension.DIMENSION_STATUS_OUTPUT_LEVEL_CODE, 
CodeStatusConvertor::new);
+    
this.suppliers.put(MetricsDimension.DIMENSION_STATUS_OUTPUT_LEVEL_CODE_GROUP, 
CodeGroupStatusConvertor::new);
+    this.suppliers
+        .put(MetricsDimension.DIMENSION_STATUS_OUTPUT_LEVEL_SUCCESS_FAILED, 
SuccessFailedStatusConvertor::new);
+  }
+
+  public StatusConvertor getConvertor(String outputLevel) {
+    if (suppliers.containsKey(outputLevel)) {
+      return suppliers.get(outputLevel).get();
+    }
+    LoggerFactory.getLogger(StatusConvertorFactory.class).error("unknown 
config value of " +
+        MetricsConfig.METRICS_DIMENSION_STATUS_OUTPUT_LEVEL + " : " + 
outputLevel
+        + ", use default level : " +
+        MetricsDimension.DIMENSION_STATUS_OUTPUT_LEVEL_SUCCESS_FAILED + " 
replace it");
+    //return default
+    return 
suppliers.get(MetricsDimension.DIMENSION_STATUS_OUTPUT_LEVEL_SUCCESS_FAILED).get();
+  }
+}
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsConfig.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/SuccessFailedStatusConvertor.java
similarity index 65%
copy from 
metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsConfig.java
copy to 
metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/SuccessFailedStatusConvertor.java
index b903f15..c2cf998 100644
--- 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/MetricsConfig.java
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/event/dimension/SuccessFailedStatusConvertor.java
@@ -15,8 +15,14 @@
  * limitations under the License.
  */
 
-package org.apache.servicecomb.metrics.core;
+package org.apache.servicecomb.metrics.core.event.dimension;
 
-public class MetricsConfig {
-  public static final String METRICS_POLLING_TIME = 
"servicecomb.metrics.window_time";
+import org.apache.servicecomb.metrics.common.MetricsDimension;
+
+public class SuccessFailedStatusConvertor implements StatusConvertor {
+  @Override
+  public String convert(boolean success, int statusCode) {
+    return success ? MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_SUCCESS
+        : MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_FAILED;
+  }
 }
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/monitor/CallMonitor.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/monitor/CallMonitor.java
index 068776e..2e61440 100644
--- 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/monitor/CallMonitor.java
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/monitor/CallMonitor.java
@@ -19,7 +19,9 @@ package org.apache.servicecomb.metrics.core.monitor;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
+import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
 import org.apache.servicecomb.metrics.common.CallMetric;
 import org.apache.servicecomb.metrics.common.DoubleMetricValue;
 import org.apache.servicecomb.metrics.common.LongMetricValue;
@@ -33,61 +35,61 @@ import com.netflix.servo.monitor.StepCounter;
 public class CallMonitor {
   private final String prefix;
 
-  private final List<BasicCounter> totalCounters;
+  private final Map<String, Map<String, DimensionCounter>> dimensionCounters;
 
-  private final List<StepCounter> tpsCounters;
-
-  public CallMonitor(String prefix, String... dimensionKeys) {
+  public CallMonitor(String prefix) {
     this.prefix = prefix;
-    this.totalCounters = new ArrayList<>();
-    this.tpsCounters = new ArrayList<>();
-    if (dimensionKeys.length == 0) {
-      this.totalCounters.add(new BasicCounter(MonitorConfig.builder(prefix + 
".total").build()));
-      this.tpsCounters.add(new StepCounter(MonitorConfig.builder(prefix + 
".tps").build()));
-    } else {
-      for (String dimensionKey : dimensionKeys) {
-        for (String option : 
MetricsDimension.getDimensionOptions(dimensionKey)) {
-          this.totalCounters
-              .add(new BasicCounter(MonitorConfig.builder(prefix + 
".total").withTag(dimensionKey, option).build()));
-          this.tpsCounters
-              .add(new StepCounter(MonitorConfig.builder(prefix + 
".tps").withTag(dimensionKey, option).build()));
-        }
-      }
-    }
+    this.dimensionCounters = new ConcurrentHashMapEx<>();
+    this.dimensionCounters.put(MetricsDimension.DIMENSION_STATUS, new 
ConcurrentHashMapEx<>());
   }
 
-  public void increment() {
-    for (int i = 0; i < totalCounters.size(); i++) {
-      totalCounters.get(i).increment();
-      tpsCounters.get(i).increment();
-    }
-  }
-
-  public void increment(String dimensionKey, String dimensionValue) {
-    for (int i = 0; i < totalCounters.size(); i++) {
-      BasicCounter totalCounter = totalCounters.get(i);
-      if (MonitorUtils.containsTagValue(totalCounter, dimensionKey, 
dimensionValue)) {
-        totalCounter.increment();
-      }
-      StepCounter tpsCounter = tpsCounters.get(i);
-      if (MonitorUtils.containsTagValue(tpsCounter, dimensionKey, 
dimensionValue)) {
-        tpsCounter.increment();
-      }
+  public void increment(String dimensionKey, String... dimensionValues) {
+    for (String dimensionValue : dimensionValues) {
+      DimensionCounter counter = dimensionCounters.get(dimensionKey)
+          .computeIfAbsent(dimensionValue, d -> new DimensionCounter(
+              new BasicCounter(MonitorConfig.builder(prefix + 
".total").withTag(dimensionKey, dimensionValue).build()),
+              new StepCounter(MonitorConfig.builder(prefix + 
".tps").withTag(dimensionKey, dimensionValue).build())));
+      counter.increment();
     }
   }
 
   public CallMetric toMetric(int windowTimeIndex) {
     List<LongMetricValue> totalValues = new ArrayList<>();
     List<DoubleMetricValue> tpsValues = new ArrayList<>();
-    for (int i = 0; i < totalCounters.size(); i++) {
-      BasicCounter totalCounter = totalCounters.get(i);
-      totalValues.add(new 
LongMetricValue(totalCounter.getValue(windowTimeIndex).longValue(),
-          MonitorUtils.convertTags(totalCounter)));
-      StepCounter tpsCounter = tpsCounters.get(i);
-      tpsValues.add(
-          new 
DoubleMetricValue(MonitorUtils.adjustValue(tpsCounter.getValue(windowTimeIndex).doubleValue()),
-              MonitorUtils.convertTags(tpsCounter)));
+    for (Map<String, DimensionCounter> dimensionCounter : 
dimensionCounters.values()) {
+      for (DimensionCounter counter : dimensionCounter.values()) {
+        totalValues.add(new 
LongMetricValue(counter.getTotal().getValue(windowTimeIndex).longValue(),
+            MonitorUtils.convertTags(counter.getTotal())));
+        tpsValues.add(
+            new 
DoubleMetricValue(MonitorUtils.adjustValue(counter.getTps().getValue(windowTimeIndex).doubleValue()),
+                MonitorUtils.convertTags(counter.getTps())));
+      }
     }
+
     return new CallMetric(this.prefix, totalValues, tpsValues);
   }
+
+  class DimensionCounter {
+    private final BasicCounter total;
+
+    private final StepCounter tps;
+
+    public BasicCounter getTotal() {
+      return total;
+    }
+
+    public StepCounter getTps() {
+      return tps;
+    }
+
+    public DimensionCounter(BasicCounter total, StepCounter tps) {
+      this.total = total;
+      this.tps = tps;
+    }
+
+    public void increment() {
+      total.increment();
+      tps.increment();
+    }
+  }
 }
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/monitor/ConsumerInvocationMonitor.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/monitor/ConsumerInvocationMonitor.java
index 9a09551..1f2f247 100644
--- 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/monitor/ConsumerInvocationMonitor.java
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/monitor/ConsumerInvocationMonitor.java
@@ -20,7 +20,6 @@ package org.apache.servicecomb.metrics.core.monitor;
 
 import org.apache.servicecomb.metrics.common.ConsumerInvocationMetric;
 import org.apache.servicecomb.metrics.common.MetricsConst;
-import org.apache.servicecomb.metrics.common.MetricsDimension;
 
 public class ConsumerInvocationMonitor extends InvocationMonitor {
   private final TimerMonitor consumerLatency;
@@ -38,7 +37,7 @@ public class ConsumerInvocationMonitor extends 
InvocationMonitor {
   public ConsumerInvocationMonitor(String operationName) {
     super(operationName, String.format(MetricsConst.CONSUMER_PREFIX_TEMPLATE, 
operationName));
     this.consumerLatency = new TimerMonitor(this.getPrefix() + 
".consumerLatency");
-    this.consumerCall = new CallMonitor(this.getPrefix() + ".consumerCall", 
MetricsDimension.DIMENSION_STATUS);
+    this.consumerCall = new CallMonitor(this.getPrefix() + ".consumerCall");
   }
 
   public ConsumerInvocationMetric toMetric(int windowTimeIndex) {
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/monitor/ProducerInvocationMonitor.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/monitor/ProducerInvocationMonitor.java
index 50a508c..9c77ec8 100644
--- 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/monitor/ProducerInvocationMonitor.java
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/monitor/ProducerInvocationMonitor.java
@@ -18,7 +18,6 @@
 package org.apache.servicecomb.metrics.core.monitor;
 
 import org.apache.servicecomb.metrics.common.MetricsConst;
-import org.apache.servicecomb.metrics.common.MetricsDimension;
 import org.apache.servicecomb.metrics.common.ProducerInvocationMetric;
 
 import com.netflix.servo.monitor.BasicCounter;
@@ -61,7 +60,7 @@ public class ProducerInvocationMonitor extends 
InvocationMonitor {
     this.lifeTimeInQueue = new TimerMonitor(this.getPrefix() + 
".lifeTimeInQueue");
     this.executionTime = new TimerMonitor(this.getPrefix() + ".executionTime");
     this.producerLatency = new TimerMonitor(this.getPrefix() + 
".producerLatency");
-    this.producerCall = new CallMonitor(this.getPrefix() + ".producerCall", 
MetricsDimension.DIMENSION_STATUS);
+    this.producerCall = new CallMonitor(this.getPrefix() + ".producerCall");
   }
 
   public ProducerInvocationMetric toMetric(int windowTimeIndex) {
diff --git 
a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestEventAndRunner.java
 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestEventAndRunner.java
index 8e87439..85cf463 100644
--- 
a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestEventAndRunner.java
+++ 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestEventAndRunner.java
@@ -36,6 +36,7 @@ import 
org.apache.servicecomb.foundation.common.utils.EventUtils;
 import org.apache.servicecomb.metrics.common.MetricsDimension;
 import org.apache.servicecomb.metrics.common.RegistryMetric;
 import org.apache.servicecomb.metrics.core.event.DefaultEventListenerManager;
+import 
org.apache.servicecomb.metrics.core.event.dimension.StatusConvertorFactory;
 import org.apache.servicecomb.metrics.core.monitor.DefaultSystemMonitor;
 import org.apache.servicecomb.metrics.core.monitor.RegistryMonitor;
 import org.apache.servicecomb.metrics.core.publish.DefaultDataSource;
@@ -74,7 +75,8 @@ public class TestEventAndRunner {
     Assert.assertEquals(intervals.size(), 3);
     Assert.assertThat(intervals, containsInAnyOrder(Arrays.asList(1000L, 
2000L, 3000L).toArray()));
 
-    new DefaultEventListenerManager(monitor);
+    new DefaultEventListenerManager(monitor, new StatusConvertorFactory(),
+        MetricsDimension.DIMENSION_STATUS_OUTPUT_LEVEL_SUCCESS_FAILED);
 
     //fun1 is a PRODUCER invocation call 2 time and all is completed
     //two time success
@@ -84,7 +86,7 @@ public class TestEventAndRunner {
             TimeUnit.MILLISECONDS.toNanos(100)));
     EventUtils
         .triggerEvent(new InvocationFinishedEvent("fun1", 
InvocationType.PRODUCER,
-            TimeUnit.MILLISECONDS.toNanos(200), 
TimeUnit.MILLISECONDS.toNanos(300), true));
+            TimeUnit.MILLISECONDS.toNanos(200), 
TimeUnit.MILLISECONDS.toNanos(300), 200, true));
 
     EventUtils.triggerEvent(new InvocationStartedEvent("fun1", 
InvocationType.PRODUCER, System.nanoTime()));
     EventUtils.triggerEvent(
@@ -92,7 +94,7 @@ public class TestEventAndRunner {
             TimeUnit.MILLISECONDS.toNanos(300)));
     EventUtils
         .triggerEvent(new InvocationFinishedEvent("fun1", 
InvocationType.PRODUCER,
-            TimeUnit.MILLISECONDS.toNanos(400), 
TimeUnit.MILLISECONDS.toNanos(700), false));
+            TimeUnit.MILLISECONDS.toNanos(400), 
TimeUnit.MILLISECONDS.toNanos(700), 500, false));
 
     
//==========================================================================
 
@@ -116,7 +118,7 @@ public class TestEventAndRunner {
             TimeUnit.MILLISECONDS.toNanos(100)));
     EventUtils
         .triggerEvent(new InvocationFinishedEvent("fun2", 
InvocationType.CONSUMER,
-            TimeUnit.MILLISECONDS.toNanos(200), 
TimeUnit.MILLISECONDS.toNanos(300), true));
+            TimeUnit.MILLISECONDS.toNanos(200), 
TimeUnit.MILLISECONDS.toNanos(300), 200, true));
 
     
//==========================================================================
 
@@ -159,16 +161,20 @@ public class TestEventAndRunner {
     Assert.assertEquals(4, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
         .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
     Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
-        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS).getValue(), 0);
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_SUCCESS)
+        .getValue(), 0);
     Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
-        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_FAILED).getValue(), 0);
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_FAILED)
+        .getValue(), 0);
 
     Assert.assertEquals(4, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
         .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
     Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
-        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS).getValue(), 0);
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_SUCCESS)
+        .getValue(), 0);
     Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
-        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_FAILED).getValue(), 0);
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_FAILED)
+        .getValue(), 0);
 
     Assert.assertEquals(1, 
model.getInstanceMetric().getConsumerMetric().getConsumerLatency().getCount());
     Assert.assertEquals(300, 
model.getInstanceMetric().getConsumerMetric().getConsumerLatency().getTotal(),
@@ -183,16 +189,20 @@ public class TestEventAndRunner {
     Assert.assertEquals(1, 
model.getInstanceMetric().getConsumerMetric().getConsumerCall()
         .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
     Assert.assertEquals(1, 
model.getInstanceMetric().getConsumerMetric().getConsumerCall()
-        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS).getValue(), 0);
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_SUCCESS)
+        .getValue(), 0);
     Assert.assertEquals(0, 
model.getInstanceMetric().getConsumerMetric().getConsumerCall()
-        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_FAILED).getValue(), 0);
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_FAILED)
+        .getValue(), 0);
 
     Assert.assertEquals(1, 
model.getInstanceMetric().getConsumerMetric().getConsumerCall()
         .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
     Assert.assertEquals(1, 
model.getInstanceMetric().getConsumerMetric().getConsumerCall()
-        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS).getValue(), 0);
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_SUCCESS)
+        .getValue(), 0);
     Assert.assertEquals(0, 
model.getInstanceMetric().getConsumerMetric().getConsumerCall()
-        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_FAILED).getValue(), 0);
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_FAILED)
+        .getValue(), 0);
 
     //check ProducerMetrics
     Assert.assertEquals(0, 
model.getProducerMetrics().get("fun1").getWaitInQueue());
@@ -217,16 +227,20 @@ public class TestEventAndRunner {
     Assert.assertEquals(2, 
model.getProducerMetrics().get("fun1").getProducerCall()
         .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
     Assert.assertEquals(1, 
model.getProducerMetrics().get("fun1").getProducerCall()
-        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS).getValue(), 0);
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_SUCCESS)
+        .getValue(), 0);
     Assert.assertEquals(1, 
model.getProducerMetrics().get("fun1").getProducerCall()
-        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_FAILED).getValue(), 0);
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_FAILED)
+        .getValue(), 0);
 
     Assert.assertEquals(2, 
model.getProducerMetrics().get("fun1").getProducerCall()
         .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
     Assert.assertEquals(1, 
model.getProducerMetrics().get("fun1").getProducerCall()
-        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS).getValue(), 0);
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_SUCCESS)
+        .getValue(), 0);
     Assert.assertEquals(1, 
model.getProducerMetrics().get("fun1").getProducerCall()
-        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_FAILED).getValue(), 0);
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_FAILED)
+        .getValue(), 0);
 
     //fun3
     Assert.assertEquals(0, 
model.getProducerMetrics().get("fun3").getWaitInQueue());
@@ -251,16 +265,20 @@ public class TestEventAndRunner {
     Assert.assertEquals(1, 
model.getProducerMetrics().get("fun3").getProducerCall()
         .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
     Assert.assertEquals(0, 
model.getProducerMetrics().get("fun3").getProducerCall()
-        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS).getValue(), 0);
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_SUCCESS)
+        .getValue(), 0);
     Assert.assertEquals(0, 
model.getProducerMetrics().get("fun3").getProducerCall()
-        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_FAILED).getValue(), 0);
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_FAILED)
+        .getValue(), 0);
 
     Assert.assertEquals(1, 
model.getProducerMetrics().get("fun3").getProducerCall()
         .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
     Assert.assertEquals(0, 
model.getProducerMetrics().get("fun3").getProducerCall()
-        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS).getValue(), 0);
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_SUCCESS)
+        .getValue(), 0);
     Assert.assertEquals(0, 
model.getProducerMetrics().get("fun3").getProducerCall()
-        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_FAILED).getValue(), 0);
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_FAILED)
+        .getValue(), 0);
 
     //check ConsumerMetrics
     //no need
@@ -273,19 +291,23 @@ public class TestEventAndRunner {
     Assert.assertEquals(1, 
model.getConsumerMetrics().get("fun2").getConsumerCall()
         .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
     Assert.assertEquals(1, 
model.getConsumerMetrics().get("fun2").getConsumerCall()
-        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS).getValue(), 0);
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_SUCCESS)
+        .getValue(), 0);
     Assert.assertEquals(0, 
model.getConsumerMetrics().get("fun2").getConsumerCall()
-        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_FAILED).getValue(), 0);
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_FAILED)
+        .getValue(), 0);
 
     Assert.assertEquals(1, 
model.getConsumerMetrics().get("fun2").getConsumerCall()
         .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
     Assert.assertEquals(1, 
model.getConsumerMetrics().get("fun2").getConsumerCall()
-        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS).getValue(), 0);
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_SUCCESS)
+        .getValue(), 0);
     Assert.assertEquals(0, 
model.getConsumerMetrics().get("fun2").getConsumerCall()
-        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_FAILED).getValue(), 0);
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_SUCCESS_FAILED_FAILED)
+        .getValue(), 0);
 
     Map<String, Number> metrics = model.toMap();
-    Assert.assertEquals(120, metrics.size());
+    Assert.assertEquals(108, metrics.size());
 
     Assert.assertEquals(1.0, 
model.getInstanceMetric().getSystemMetric().getCpuLoad(), 0);
     Assert.assertEquals(2, 
model.getInstanceMetric().getSystemMetric().getCpuRunningThreads(), 0);
diff --git 
a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestStatusDimension.java
 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestStatusDimension.java
new file mode 100644
index 0000000..0a113fb
--- /dev/null
+++ 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestStatusDimension.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.servicecomb.metrics.core;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.servicecomb.core.metrics.InvocationFinishedEvent;
+import org.apache.servicecomb.core.metrics.InvocationStartProcessingEvent;
+import org.apache.servicecomb.core.metrics.InvocationStartedEvent;
+import org.apache.servicecomb.foundation.common.utils.EventUtils;
+import org.apache.servicecomb.metrics.common.MetricsDimension;
+import org.apache.servicecomb.metrics.common.RegistryMetric;
+import org.apache.servicecomb.metrics.core.event.DefaultEventListenerManager;
+import 
org.apache.servicecomb.metrics.core.event.dimension.StatusConvertorFactory;
+import org.apache.servicecomb.metrics.core.monitor.DefaultSystemMonitor;
+import org.apache.servicecomb.metrics.core.monitor.RegistryMonitor;
+import org.apache.servicecomb.metrics.core.publish.DefaultDataSource;
+import org.apache.servicecomb.swagger.invocation.InvocationType;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestStatusDimension {
+
+  @Test
+  public void testCodeGroupDimension() throws InterruptedException {
+    RegistryMetric model = 
prepare(MetricsDimension.DIMENSION_STATUS_OUTPUT_LEVEL_CODE_GROUP);
+
+    Assert.assertEquals(5, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
+    Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_CODE_GROUP_2XX)
+        .getValue(), 0);
+    Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_CODE_GROUP_3XX)
+        .getValue(), 0);
+    Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_CODE_GROUP_4XX)
+        .getValue(), 0);
+    Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_CODE_GROUP_5XX)
+        .getValue(), 0);
+    Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_CODE_GROUP_OTHER)
+        .getValue(), 0);
+
+    Assert.assertEquals(1, 
model.getInstanceMetric().getConsumerMetric().getConsumerCall()
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
+    Assert.assertEquals(1, 
model.getInstanceMetric().getConsumerMetric().getConsumerCall()
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_CODE_GROUP_2XX)
+        .getValue(), 0);
+  }
+
+  @Test
+  public void testCodeDimension() throws InterruptedException {
+    RegistryMetric model = 
prepare(MetricsDimension.DIMENSION_STATUS_OUTPUT_LEVEL_CODE);
+
+    Assert.assertEquals(5, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
+    Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, "222")
+        .getValue(), 0);
+    Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, "333")
+        .getValue(), 0);
+    Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, "444")
+        .getValue(), 0);
+    Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, "555")
+        .getValue(), 0);
+    Assert.assertEquals(1, 
model.getInstanceMetric().getProducerMetric().getProducerCall()
+        .getTpsValue(MetricsDimension.DIMENSION_STATUS, "666")
+        .getValue(), 0);
+
+    Assert.assertEquals(1, 
model.getInstanceMetric().getConsumerMetric().getConsumerCall()
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, 
MetricsDimension.DIMENSION_STATUS_ALL).getValue(), 0);
+    Assert.assertEquals(1, 
model.getInstanceMetric().getConsumerMetric().getConsumerCall()
+        .getTotalValue(MetricsDimension.DIMENSION_STATUS, "200")
+        .getValue(), 0);
+  }
+
+  private RegistryMetric prepare(String outputLevel) throws 
InterruptedException {
+    DefaultSystemMonitor systemMonitor = new DefaultSystemMonitor();
+    RegistryMonitor monitor = new RegistryMonitor(systemMonitor);
+    DefaultDataSource dataSource = new DefaultDataSource(monitor, 
"1000,2000,3000");
+
+    new DefaultEventListenerManager(monitor, new StatusConvertorFactory(), 
outputLevel);
+
+    EventUtils.triggerEvent(new InvocationStartedEvent("fun1", 
InvocationType.PRODUCER, System.nanoTime()));
+    EventUtils.triggerEvent(
+        new InvocationStartProcessingEvent("fun1", InvocationType.PRODUCER,
+            TimeUnit.MILLISECONDS.toNanos(100)));
+    EventUtils
+        .triggerEvent(new InvocationFinishedEvent("fun1", 
InvocationType.PRODUCER,
+            TimeUnit.MILLISECONDS.toNanos(200), 
TimeUnit.MILLISECONDS.toNanos(300), 222, true));
+
+    EventUtils.triggerEvent(new InvocationStartedEvent("fun1", 
InvocationType.PRODUCER, System.nanoTime()));
+    EventUtils.triggerEvent(
+        new InvocationStartProcessingEvent("fun1", InvocationType.PRODUCER,
+            TimeUnit.MILLISECONDS.toNanos(100)));
+    EventUtils
+        .triggerEvent(new InvocationFinishedEvent("fun1", 
InvocationType.PRODUCER,
+            TimeUnit.MILLISECONDS.toNanos(200), 
TimeUnit.MILLISECONDS.toNanos(300), 333, false));
+
+    EventUtils.triggerEvent(new InvocationStartedEvent("fun1", 
InvocationType.PRODUCER, System.nanoTime()));
+    EventUtils.triggerEvent(
+        new InvocationStartProcessingEvent("fun1", InvocationType.PRODUCER,
+            TimeUnit.MILLISECONDS.toNanos(100)));
+    EventUtils
+        .triggerEvent(new InvocationFinishedEvent("fun1", 
InvocationType.PRODUCER,
+            TimeUnit.MILLISECONDS.toNanos(200), 
TimeUnit.MILLISECONDS.toNanos(300), 444, false));
+
+    EventUtils.triggerEvent(new InvocationStartedEvent("fun1", 
InvocationType.PRODUCER, System.nanoTime()));
+    EventUtils.triggerEvent(
+        new InvocationStartProcessingEvent("fun1", InvocationType.PRODUCER,
+            TimeUnit.MILLISECONDS.toNanos(100)));
+    EventUtils
+        .triggerEvent(new InvocationFinishedEvent("fun1", 
InvocationType.PRODUCER,
+            TimeUnit.MILLISECONDS.toNanos(200), 
TimeUnit.MILLISECONDS.toNanos(300), 555, false));
+
+    EventUtils.triggerEvent(new InvocationStartedEvent("fun1", 
InvocationType.PRODUCER, System.nanoTime()));
+    EventUtils.triggerEvent(
+        new InvocationStartProcessingEvent("fun1", InvocationType.PRODUCER,
+            TimeUnit.MILLISECONDS.toNanos(100)));
+    EventUtils
+        .triggerEvent(new InvocationFinishedEvent("fun1", 
InvocationType.PRODUCER,
+            TimeUnit.MILLISECONDS.toNanos(200), 
TimeUnit.MILLISECONDS.toNanos(300), 666, false));
+
+    //fun2 is a CONSUMER invocation call once and completed
+    EventUtils.triggerEvent(new InvocationStartedEvent("fun2", 
InvocationType.CONSUMER, System.nanoTime()));
+    EventUtils.triggerEvent(
+        new InvocationStartProcessingEvent("fun2", InvocationType.CONSUMER,
+            TimeUnit.MILLISECONDS.toNanos(100)));
+    EventUtils
+        .triggerEvent(new InvocationFinishedEvent("fun2", 
InvocationType.CONSUMER,
+            TimeUnit.MILLISECONDS.toNanos(200), 
TimeUnit.MILLISECONDS.toNanos(300), 200, true));
+
+    //sim lease one window time
+    Thread.sleep(1000);
+
+    return dataSource.getRegistryMetric(1000);
+  }
+}
diff --git 
a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerInvoke.java
 
b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerInvoke.java
index ba8c126..020c926 100644
--- 
a/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerInvoke.java
+++ 
b/transports/transport-highway/src/main/java/org/apache/servicecomb/transport/highway/HighwayServerInvoke.java
@@ -134,7 +134,7 @@ public class HighwayServerInvoke {
     invocation.next(response -> {
       sendResponse(invocation.getContext(), response);
       endMetrics(invocation);
-      invocation.triggerFinishedEvent(response.isSuccessed());
+      invocation.triggerFinishedEvent(response.getStatusCode(), 
response.isSuccessed());
     });
   }
 

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to