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

albumenj pushed a commit to branch 3.2
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.2 by this push:
     new 2f4944e853 Interface level registry metrics (#11786)
2f4944e853 is described below

commit 2f4944e85385978e24486338cb41b4620ab00339
Author: wxbty <[email protected]>
AuthorDate: Fri Mar 17 13:46:04 2023 +0800

    Interface level registry metrics (#11786)
    
    * fix
    
    * remove unuse
    
    * add serviceKey subscribe
    
    * fix method refact
    
    * remove unuse
    
    * remove unuse
    
    * fix npe
    
    * fix npe
    
    * fix npe
    
    * add event validate
    
    * fix testcase
    
    ---------
    
    Co-authored-by: x-shadow-man <[email protected]>
---
 .../rpc/cluster/directory/AbstractDirectory.java   | 10 +--
 .../apache/dubbo/rpc/model/ApplicationModel.java   |  5 ++
 .../org/apache/dubbo/config/ServiceConfig.java     | 29 ++++++-
 .../config/deploy/DefaultApplicationDeployer.java  |  6 +-
 .../collector/ApplicationMetricsCollector.java     |  2 +-
 .../event/SimpleMetricsEventMulticaster.java       | 13 +++-
 .../dubbo/metrics/model/ApplicationMetric.java     |  8 ++
 .../org/apache/dubbo/metrics/model/MetricsKey.java | 10 +++
 .../collector/MetadataMetricsCollector.java        |  2 +-
 .../metadata/event/MetricsPushListener.java        |  4 +-
 .../metadata/event/MetricsSubscribeListener.java   |  4 +-
 .../collector/RegistryMetricsCollector.java        | 26 +++++--
 .../collector/stat/RegistryStatComposite.java      | 90 ++++++++++++++++------
 .../registry/event/MetricsNotifyListener.java      |  6 +-
 .../registry/event/MetricsRegisterListener.java    | 20 ++---
 .../event/MetricsServiceRegisterListener.java      | 51 ++++++++++++
 .../event/MetricsServiceSubscribeListener.java     | 52 +++++++++++++
 .../registry/event/MetricsSubscribeListener.java   | 10 +--
 .../metrics/registry/event/RegistryEvent.java      | 87 ++++++++++++++++++---
 .../event/RegistryMetricsEventMulticaster.java     |  2 +
 .../collector/RegistryMetricsCollectorTest.java    |  8 +-
 .../collector/RegistryMetricsSampleTest.java       |  6 +-
 .../collector/RegistryStatCompositeTest.java       | 18 ++---
 .../registry/client/ServiceDiscoveryRegistry.java  | 18 ++++-
 24 files changed, 391 insertions(+), 96 deletions(-)

diff --git 
a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
 
b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
index 9d3dc1e827..9109286382 100644
--- 
a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
+++ 
b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
@@ -396,7 +396,7 @@ public abstract class AbstractDirectory<T> implements 
Directory<T> {
 
     @Override
     public void addDisabledInvoker(Invoker<T> invoker) {
-        publishMetricsEvent(new 
RegistryEvent.MetricsDirectoryEvent(applicationModel, 
RegistryEvent.Type.D_DISABLE));
+        publishMetricsEvent(new 
RegistryEvent.MetricsDirectoryEvent(applicationModel, 
RegistryEvent.ApplicationType.D_DISABLE));
         if (invokers.contains(invoker)) {
             disabledInvokers.add(invoker);
             removeValidInvoker(invoker);
@@ -406,7 +406,7 @@ public abstract class AbstractDirectory<T> implements 
Directory<T> {
 
     @Override
     public void recoverDisabledInvoker(Invoker<T> invoker) {
-        publishMetricsEvent(new 
RegistryEvent.MetricsDirectoryEvent(applicationModel, 
RegistryEvent.Type.D_RECOVER_DISABLE));
+        publishMetricsEvent(new 
RegistryEvent.MetricsDirectoryEvent(applicationModel, 
RegistryEvent.ApplicationType.D_RECOVER_DISABLE));
         if (disabledInvokers.remove(invoker)) {
             try {
                 addValidInvoker(invoker);
@@ -470,7 +470,7 @@ public abstract class AbstractDirectory<T> implements 
Directory<T> {
         this.invokers = invokers;
         refreshInvokerInternal();
         this.invokersInitialized = true;
-        publishMetricsEvent(new 
RegistryEvent.MetricsDirectoryEvent(applicationModel, 
RegistryEvent.Type.D_CURRENT, invokers.size()));
+        publishMetricsEvent(new 
RegistryEvent.MetricsDirectoryEvent(applicationModel, 
RegistryEvent.ApplicationType.D_CURRENT, invokers.size()));
     }
 
     protected void destroyInvokers() {
@@ -481,14 +481,14 @@ public abstract class AbstractDirectory<T> implements 
Directory<T> {
     }
 
     private boolean addValidInvoker(Invoker<T> invoker) {
-        publishMetricsEvent(new 
RegistryEvent.MetricsDirectoryEvent(applicationModel, 
RegistryEvent.Type.D_VALID));
+        publishMetricsEvent(new 
RegistryEvent.MetricsDirectoryEvent(applicationModel, 
RegistryEvent.ApplicationType.D_VALID));
         synchronized (this.validInvokers) {
             return this.validInvokers.add(invoker);
         }
     }
 
     private boolean removeValidInvoker(Invoker<T> invoker) {
-        publishMetricsEvent(new 
RegistryEvent.MetricsDirectoryEvent(applicationModel, 
RegistryEvent.Type.D_UN_VALID));
+        publishMetricsEvent(new 
RegistryEvent.MetricsDirectoryEvent(applicationModel, 
RegistryEvent.ApplicationType.D_UN_VALID));
         synchronized (this.validInvokers) {
             return this.validInvokers.remove(invoker);
         }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java 
b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java
index 5f7800346a..c0f1e3cf10 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java
@@ -84,6 +84,7 @@ public class ApplicationModel extends ScopeModel {
      * During destroying the default FrameworkModel, the 
FrameworkModel.defaultModel() or ApplicationModel.defaultModel()
      * will return a broken model, maybe cause unpredictable problem.
      * Recommendation: Avoid using the default model as much as possible.
+     *
      * @return the global default ApplicationModel
      */
     public static ApplicationModel defaultModel() {
@@ -224,6 +225,10 @@ public class ApplicationModel extends ScopeModel {
         return ExecutorRepository.getInstance(this);
     }
 
+    public boolean NotExistApplicationConfig() {
+        return !getApplicationConfigManager().getApplication().isPresent();
+    }
+
     public ApplicationConfig getCurrentConfig() {
         return getApplicationConfigManager().getApplicationOrElseThrow();
     }
diff --git 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
index 204d09777d..940da27c35 100644
--- 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
+++ 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java
@@ -36,13 +36,18 @@ import 
org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker;
 import org.apache.dubbo.config.support.Parameter;
 import org.apache.dubbo.config.utils.ConfigValidationUtils;
 import org.apache.dubbo.metadata.ServiceNameMapping;
+import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster;
+import org.apache.dubbo.metrics.model.TimePair;
+import org.apache.dubbo.metrics.registry.event.RegistryEvent;
 import org.apache.dubbo.registry.client.metadata.MetadataUtils;
 import org.apache.dubbo.rpc.Exporter;
 import org.apache.dubbo.rpc.Invoker;
 import org.apache.dubbo.rpc.Protocol;
 import org.apache.dubbo.rpc.ProxyFactory;
+import org.apache.dubbo.rpc.RpcException;
 import org.apache.dubbo.rpc.ServerService;
 import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
+import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.ModuleModel;
 import org.apache.dubbo.rpc.model.ModuleServiceRepository;
 import org.apache.dubbo.rpc.model.ProviderModel;
@@ -421,6 +426,17 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> 
{
 
         List<URL> registryURLs = ConfigValidationUtils.loadRegistries(this, 
true);
 
+        TimePair timePair = TimePair.start();
+        ApplicationModel applicationModel = module.getApplicationModel();
+        try {
+            
applicationModel.getBeanFactory().getBean(GlobalMetricsEventMulticaster.class);
+        } catch (Throwable t) {
+            applicationModel = ApplicationModel.defaultModel();
+        }
+        GlobalMetricsEventMulticaster eventMulticaster = 
applicationModel.getBeanFactory().getBean(GlobalMetricsEventMulticaster.class);
+        int size = protocols.size() * registryURLs.size();
+        eventMulticaster.publishEvent(new 
RegistryEvent.MetricsServiceRegisterEvent(applicationModel, timePair, 
getUniqueServiceName(), size));
+
         for (ProtocolConfig protocolConfig : protocols) {
             String pathKey = URL.buildKey(getContextPath(protocolConfig)
                 .map(p -> p + "/" + path)
@@ -430,9 +446,14 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> 
{
                 // In case user specified path, register service one more time 
to map it to path.
                 repository.registerService(pathKey, interfaceClass);
             }
-            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
+            try {
+                doExportUrlsFor1Protocol(protocolConfig, registryURLs);
+            } catch (RpcException e) {
+                eventMulticaster.publishErrorEvent(new 
RegistryEvent.MetricsServiceRegisterEvent(applicationModel, timePair, 
getUniqueServiceName(), registryURLs.size()));
+                throw e;
+            }
         }
-
+        eventMulticaster.publishFinishEvent(new 
RegistryEvent.MetricsServiceRegisterEvent(applicationModel, timePair, 
getUniqueServiceName(), size));
         providerModel.setServiceUrls(urls);
     }
 
@@ -665,8 +686,8 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
                     protocols.addAll(Arrays.asList(extProtocols));
                 }
                 // export extra protocols
-                for(String protocol : protocols) {
-                    if(StringUtils.isNotBlank(protocol)){
+                for (String protocol : protocols) {
+                    if (StringUtils.isNotBlank(protocol)) {
                         URL localUrl = URLBuilder.from(url).
                             setProtocol(protocol).
                             build();
diff --git 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java
 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java
index 3e4221737a..12d29ff2e5 100644
--- 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java
+++ 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java
@@ -831,13 +831,13 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
     private void registerServiceInstance() {
         TimePair timePair = TimePair.start();
         GlobalMetricsEventMulticaster eventMulticaster = 
applicationModel.getBeanFactory().getBean(GlobalMetricsEventMulticaster.class);
-        eventMulticaster.publishEvent(new 
RegistryEvent.MetricsRegisterEvent(applicationModel, timePair));
+        eventMulticaster.publishEvent(new 
RegistryEvent.MetricsApplicationRegisterEvent(applicationModel, timePair));
         try {
             registered = true;
             
ServiceInstanceMetadataUtils.registerMetadataAndInstance(applicationModel);
-            eventMulticaster.publishFinishEvent(new 
RegistryEvent.MetricsRegisterEvent(applicationModel, timePair));
+            eventMulticaster.publishFinishEvent(new 
RegistryEvent.MetricsApplicationRegisterEvent(applicationModel, timePair));
         } catch (Exception e) {
-            eventMulticaster.publishErrorEvent(new 
RegistryEvent.MetricsRegisterEvent(applicationModel, timePair));
+            eventMulticaster.publishErrorEvent(new 
RegistryEvent.MetricsApplicationRegisterEvent(applicationModel, timePair));
             logger.error(CONFIG_REGISTER_INSTANCE_ERROR, "configuration server 
disconnected", "", "Register instance error.", e);
         }
         if (registered) {
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/ApplicationMetricsCollector.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/ApplicationMetricsCollector.java
index c1dc63e5b2..118b87cda9 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/ApplicationMetricsCollector.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/ApplicationMetricsCollector.java
@@ -29,6 +29,6 @@ public interface ApplicationMetricsCollector<T, E extends 
MetricsEvent> extends
 
     void increment(String applicationName, T type);
 
-    void addRT(String applicationName, String registryOpType, Long 
responseTime);
+    void addApplicationRT(String applicationName, String registryOpType, Long 
responseTime);
 }
 
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticaster.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticaster.java
index c3f187c82e..64e393cc53 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticaster.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticaster.java
@@ -19,6 +19,7 @@ package org.apache.dubbo.metrics.event;
 
 import org.apache.dubbo.metrics.listener.MetricsLifeListener;
 import org.apache.dubbo.metrics.listener.MetricsListener;
+import org.apache.dubbo.rpc.model.ApplicationModel;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -26,7 +27,7 @@ import java.util.List;
 import java.util.function.Consumer;
 
 /**
- *  A simple event publisher that defines lifecycle events and supports rt 
events
+ * A simple event publisher that defines lifecycle events and supports rt 
events
  */
 public class SimpleMetricsEventMulticaster implements MetricsEventMulticaster {
     private final List<MetricsListener<?>> listeners = 
Collections.synchronizedList(new ArrayList<>());
@@ -52,6 +53,7 @@ public class SimpleMetricsEventMulticaster implements 
MetricsEventMulticaster {
         if (event instanceof EmptyEvent) {
             return;
         }
+        if (validateIfSourceInstanceOfApplicationModel(event)) return;
         for (MetricsListener listener : listeners) {
             if (listener.isSupport(event)) {
                 listener.onEvent(event);
@@ -59,6 +61,14 @@ public class SimpleMetricsEventMulticaster implements 
MetricsEventMulticaster {
         }
     }
 
+    private boolean validateIfSourceInstanceOfApplicationModel(MetricsEvent 
event) {
+        if (event.getSource() instanceof ApplicationModel) {
+            // Check if exist application config
+            return ((ApplicationModel) 
event.getSource()).NotExistApplicationConfig();
+        }
+        return false;
+    }
+
     @Override
     @SuppressWarnings({"unchecked"})
     public void publishFinishEvent(MetricsEvent event) {
@@ -73,6 +83,7 @@ public class SimpleMetricsEventMulticaster implements 
MetricsEventMulticaster {
 
     @SuppressWarnings({"rawtypes"})
     private void publishTimeEvent(MetricsEvent event, 
Consumer<MetricsLifeListener> consumer) {
+        if (validateIfSourceInstanceOfApplicationModel(event)) return;
         if (event instanceof EmptyEvent) {
             return;
         }
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ApplicationMetric.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ApplicationMetric.java
index b0e583806f..cc1b4abba6 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ApplicationMetric.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ApplicationMetric.java
@@ -23,6 +23,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import static org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME;
+import static 
org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY;
 import static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP;
 import static 
org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;
 import static 
org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_VERSION_KEY;
@@ -60,4 +61,11 @@ public class ApplicationMetric implements Metric {
         tags.put(MetricsKey.METADATA_GIT_COMMITID_METRIC.getName(), commitId);
         return tags;
     }
+
+    public static Map<String, String> getServiceTags(String appAndServiceName) 
{
+        String[] keys = appAndServiceName.split("_");
+        Map<String, String> tags = getTagsByName(keys[0]);
+        tags.put(TAG_INTERFACE_KEY, keys[1]);
+        return tags;
+    }
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKey.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKey.java
index 8fe6d1a96e..a931adcb19 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKey.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKey.java
@@ -91,6 +91,16 @@ public enum MetricsKey {
     METADATA_SUBSCRIBE_METRIC_NUM("dubbo.metadata.subscribe.num.total", "Total 
Metadata Subscribe Num"),
     
METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED("dubbo.metadata.subscribe.num.succeed.total",
 "Succeed Metadata Subscribe Num"),
     
METADATA_SUBSCRIBE_METRIC_NUM_FAILED("dubbo.metadata.subscribe.num.failed.total",
 "Failed Metadata Subscribe Num"),
+
+    // register service metrics key
+    SERVICE_REGISTER_METRIC_REQUESTS("dubbo.registry.register.service.total", 
"Total Service-Level Register Requests"),
+    
SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED("dubbo.registry.register.service.succeed.total",
 "Succeed Service-Level Register Requests"),
+    
SERVICE_REGISTER_METRIC_REQUESTS_FAILED("dubbo.registry.register.service.failed.total",
 "Failed Service-Level Register Requests"),
+
+    // subscribe metrics key
+    SERVICE_SUBSCRIBE_METRIC_NUM("dubbo.registry.subscribe.service.num.total", 
"Total Service-Level Subscribe Num"),
+    
SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED("dubbo.registry.subscribe.service.num.succeed.total",
 "Succeed Service-Level Num"),
+    
SERVICE_SUBSCRIBE_METRIC_NUM_FAILED("dubbo.registry.subscribe.service.num.failed.total",
 "Failed Service-Level Num"),
     METADATA_GIT_COMMITID_METRIC("git.commit.id","Git Commit Id Metrics");
     // consumer metrics key
     ;
diff --git 
a/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/collector/MetadataMetricsCollector.java
 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/collector/MetadataMetricsCollector.java
index c9140a288c..405abe7390 100644
--- 
a/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/collector/MetadataMetricsCollector.java
+++ 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/collector/MetadataMetricsCollector.java
@@ -72,7 +72,7 @@ public class MetadataMetricsCollector implements 
ApplicationMetricsCollector<Met
     }
 
     @Override
-    public void addRT(String applicationName, String registryOpType, Long 
responseTime) {
+    public void addApplicationRT(String applicationName, String 
registryOpType, Long responseTime) {
         stats.calcRt(applicationName, registryOpType, responseTime);
     }
 
diff --git 
a/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetricsPushListener.java
 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetricsPushListener.java
index d08ec366c8..1c3352cf50 100644
--- 
a/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetricsPushListener.java
+++ 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetricsPushListener.java
@@ -38,12 +38,12 @@ public class MetricsPushListener implements 
MetricsLifeListener<MetadataEvent.Pu
     @Override
     public void onEventFinish(MetadataEvent.PushEvent event) {
         event.getCollector().increment(event.getSource().getApplicationName(), 
MetadataEvent.Type.P_SUCCEED);
-        event.getCollector().addRT(event.getSource().getApplicationName(), 
OP_TYPE_PUSH, event.getTimePair().calc());
+        
event.getCollector().addApplicationRT(event.getSource().getApplicationName(), 
OP_TYPE_PUSH, event.getTimePair().calc());
     }
 
     @Override
     public void onEventError(MetadataEvent.PushEvent event) {
         event.getCollector().increment(event.getSource().getApplicationName(), 
MetadataEvent.Type.P_FAILED);
-        event.getCollector().addRT(event.getSource().getApplicationName(), 
OP_TYPE_PUSH, event.getTimePair().calc());
+        
event.getCollector().addApplicationRT(event.getSource().getApplicationName(), 
OP_TYPE_PUSH, event.getTimePair().calc());
     }
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetricsSubscribeListener.java
 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetricsSubscribeListener.java
index a247f539a5..1e17acc778 100644
--- 
a/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetricsSubscribeListener.java
+++ 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetricsSubscribeListener.java
@@ -37,13 +37,13 @@ public class MetricsSubscribeListener implements 
MetricsLifeListener<MetadataEve
     @Override
     public void onEventFinish(MetadataEvent.SubscribeEvent event) {
         event.getCollector().increment(event.getSource().getApplicationName(), 
MetadataEvent.Type.S_SUCCEED);
-        event.getCollector().addRT(event.getSource().getApplicationName(), 
OP_TYPE_SUBSCRIBE, event.getTimePair().calc());
+        
event.getCollector().addApplicationRT(event.getSource().getApplicationName(), 
OP_TYPE_SUBSCRIBE, event.getTimePair().calc());
     }
 
     @Override
     public void onEventError(MetadataEvent.SubscribeEvent event) {
         event.getCollector().increment(event.getSource().getApplicationName(), 
MetadataEvent.Type.S_FAILED);
-        event.getCollector().addRT(event.getSource().getApplicationName(), 
OP_TYPE_SUBSCRIBE, event.getTimePair().calc());
+        
event.getCollector().addApplicationRT(event.getSource().getApplicationName(), 
OP_TYPE_SUBSCRIBE, event.getTimePair().calc());
     }
 
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryMetricsCollector.java
 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryMetricsCollector.java
index 37ee237500..b079c5c0ca 100644
--- 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryMetricsCollector.java
+++ 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryMetricsCollector.java
@@ -39,7 +39,7 @@ import java.util.Optional;
  * Registry implementation of {@link MetricsCollector}
  */
 @Activate
-public class RegistryMetricsCollector implements 
ApplicationMetricsCollector<RegistryEvent.Type, RegistryEvent> {
+public class RegistryMetricsCollector implements 
ApplicationMetricsCollector<RegistryEvent.ApplicationType, RegistryEvent> {
 
     private Boolean collectEnabled = null;
     private final RegistryStatComposite stats;
@@ -67,31 +67,43 @@ public class RegistryMetricsCollector implements 
ApplicationMetricsCollector<Reg
         return Optional.ofNullable(collectEnabled).orElse(false);
     }
 
-    public void setNum(RegistryEvent.Type registryType, String 
applicationName, Map<String, Integer> lastNumMap) {
+    public void setNum(RegistryEvent.ServiceType registryType, String 
applicationName, Map<String, Integer> lastNumMap) {
         lastNumMap.forEach((serviceKey, num) ->
             this.stats.setServiceKey(registryType, applicationName, 
serviceKey, num));
     }
 
-    public void setNum(RegistryEvent.Type registryType, String 
applicationName, Integer num) {
+    public void setNum(RegistryEvent.ApplicationType registryType, String 
applicationName, Integer num) {
         this.stats.setApplicationKey(registryType, applicationName, num);
     }
 
 
     @Override
-    public void increment(String applicationName, RegistryEvent.Type 
registryType) {
+    public void increment(String applicationName, 
RegistryEvent.ApplicationType registryType) {
         this.stats.increment(registryType, applicationName);
     }
 
+    public void increment(String applicationName, 
RegistryEvent.ApplicationType registryType, int size) {
+        this.stats.incrementSize(registryType, applicationName, size);
+    }
+
+    public void incrementServiceKey(String applicationName, String serviceKey, 
RegistryEvent.ServiceType registryType, int size) {
+        this.stats.incrementServiceKey(registryType, applicationName, 
serviceKey, size);
+    }
+
     @Override
-    public void addRT(String applicationName, String registryOpType, Long 
responseTime) {
-        stats.calcRt(applicationName, registryOpType, responseTime);
+    public void addApplicationRT(String applicationName, String 
registryOpType, Long responseTime) {
+        stats.calcApplicationRt(applicationName, registryOpType, responseTime);
+    }
+
+    public void addServiceKeyRT(String applicationName, String serviceKey, 
String registryOpType, Long responseTime) {
+        stats.calcServiceKeyRt(applicationName, serviceKey, registryOpType, 
responseTime);
     }
 
     @Override
     public List<MetricSample> collect() {
         List<MetricSample> list = new ArrayList<>();
         if (!isCollectEnabled()) {
-           return list;
+            return list;
         }
         list.addAll(stats.exportNumMetrics());
         list.addAll(stats.exportRtMetrics());
diff --git 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/stat/RegistryStatComposite.java
 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/stat/RegistryStatComposite.java
index 9bfa2532e5..864499bbc3 100644
--- 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/stat/RegistryStatComposite.java
+++ 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/stat/RegistryStatComposite.java
@@ -36,6 +36,7 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.LongAccumulator;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -46,21 +47,35 @@ import java.util.stream.Collectors;
 public class RegistryStatComposite implements MetricsExport {
 
 
-    public Map<RegistryEvent.Type, Map<String, AtomicLong>> numStats = new 
ConcurrentHashMap<>();
-    public Map<RegistryEvent.Type, Map<ServiceKeyMetric, AtomicLong>> skStats 
= new ConcurrentHashMap<>();
-    public List<LongContainer<? extends Number>> rtStats = new ArrayList<>();
+    public Map<RegistryEvent.ApplicationType, Map<String, AtomicLong>> 
applicationNumStats = new ConcurrentHashMap<>();
+    public Map<RegistryEvent.ServiceType, Map<ServiceKeyMetric, AtomicLong>> 
serviceNumStats = new ConcurrentHashMap<>();
+    public Map<RegistryEvent.ServiceType, Map<ServiceKeyMetric, AtomicLong>> 
skStats = new ConcurrentHashMap<>();
+    public List<LongContainer<? extends Number>> appRtStats = new 
ArrayList<>();
+    public List<LongContainer<? extends Number>> serviceRtStats = new 
ArrayList<>();
     public static String OP_TYPE_REGISTER = "register";
     public static String OP_TYPE_SUBSCRIBE = "subscribe";
     public static String OP_TYPE_NOTIFY = "notify";
+    public static String OP_TYPE_REGISTER_SERVICE = "register.service";
+    public static String OP_TYPE_SUBSCRIBE_SERVICE = "subscribe.service";
 
     public RegistryStatComposite() {
-        for (RegistryEvent.Type type : RegistryEvent.Type.values()) {
-            numStats.put(type, new ConcurrentHashMap<>());
+        for (RegistryEvent.ApplicationType type : 
RegistryEvent.ApplicationType.values()) {
+            // Application key and increment val
+            applicationNumStats.put(type, new ConcurrentHashMap<>());
         }
 
-        rtStats.addAll(initStats(OP_TYPE_REGISTER));
-        rtStats.addAll(initStats(OP_TYPE_SUBSCRIBE));
-        rtStats.addAll(initStats(OP_TYPE_NOTIFY));
+        for (RegistryEvent.ServiceType type : 
RegistryEvent.ServiceType.values()) {
+            // Service key
+            skStats.put(type, new ConcurrentHashMap<>());
+        }
+
+
+        appRtStats.addAll(initStats(OP_TYPE_REGISTER));
+        appRtStats.addAll(initStats(OP_TYPE_SUBSCRIBE));
+        appRtStats.addAll(initStats(OP_TYPE_NOTIFY));
+
+        serviceRtStats.addAll(initStats(OP_TYPE_REGISTER_SERVICE));
+        serviceRtStats.addAll(initStats(OP_TYPE_SUBSCRIBE_SERVICE));
     }
 
     private List<LongContainer<? extends Number>> initStats(String 
registryOpType) {
@@ -72,7 +87,7 @@ public class RegistryStatComposite implements MetricsExport {
         // AvgContainer is a special counter that stores the number of times 
but outputs function of sum/times
         AtomicLongContainer avgContainer = new AtomicLongContainer(new 
MetricsKeyWrapper(registryOpType, MetricsKey.METRIC_RT_AVG), (k, v) -> 
v.incrementAndGet());
         avgContainer.setValueSupplier(applicationName -> {
-            LongContainer<? extends Number> totalContainer = 
rtStats.stream().filter(longContainer -> 
longContainer.isKeyWrapper(MetricsKey.METRIC_RT_SUM, 
registryOpType)).findFirst().get();
+            LongContainer<? extends Number> totalContainer = 
appRtStats.stream().filter(longContainer -> 
longContainer.isKeyWrapper(MetricsKey.METRIC_RT_SUM, 
registryOpType)).findFirst().get();
             AtomicLong totalRtTimes = avgContainer.get(applicationName);
             AtomicLong totalRtSum = (AtomicLong) 
totalContainer.get(applicationName);
             return totalRtSum.get() / totalRtTimes.get();
@@ -81,41 +96,60 @@ public class RegistryStatComposite implements MetricsExport 
{
         return singleRtStats;
     }
 
-    public void setApplicationKey(RegistryEvent.Type type, String 
applicationName, int num) {
-        if (!numStats.containsKey(type)) {
+    public void setApplicationKey(RegistryEvent.ApplicationType type, String 
applicationName, int num) {
+        if (!applicationNumStats.containsKey(type)) {
             return;
         }
-        numStats.get(type).computeIfAbsent(applicationName, k -> new 
AtomicLong(0L)).set(num);
+        applicationNumStats.get(type).computeIfAbsent(applicationName, k -> 
new AtomicLong(0L)).set(num);
     }
 
-    public void setServiceKey(RegistryEvent.Type type, String applicationName, 
String serviceKey, int num) {
+    public void setServiceKey(RegistryEvent.ServiceType type, String 
applicationName, String serviceKey, int num) {
         if (!skStats.containsKey(type)) {
             return;
         }
         skStats.get(type).computeIfAbsent(new 
ServiceKeyMetric(applicationName, serviceKey), k -> new 
AtomicLong(0L)).set(num);
     }
 
-    public void increment(RegistryEvent.Type type, String applicationName) {
-        if (!numStats.containsKey(type)) {
+    public void increment(RegistryEvent.ApplicationType type, String 
applicationName) {
+        incrementSize(type, applicationName, 1);
+    }
+
+    public void incrementServiceKey(RegistryEvent.ServiceType type, String 
applicationName, String serviceKey, int size) {
+        if (!skStats.containsKey(type)) {
+            return;
+        }
+        skStats.get(type).computeIfAbsent(new 
ServiceKeyMetric(applicationName, serviceKey), k -> new 
AtomicLong(0L)).getAndAdd(size);
+    }
+
+    public void incrementSize(RegistryEvent.ApplicationType type, String 
applicationName, int size) {
+        if (!applicationNumStats.containsKey(type)) {
             return;
         }
-        numStats.get(type).computeIfAbsent(applicationName, k -> new 
AtomicLong(0L)).incrementAndGet();
+        applicationNumStats.get(type).computeIfAbsent(applicationName, k -> 
new AtomicLong(0L)).getAndAdd(size);
     }
 
     @SuppressWarnings({"rawtypes", "unchecked"})
-    public void calcRt(String applicationName, String registryOpType, Long 
responseTime) {
-        for (LongContainer container : rtStats.stream().filter(longContainer 
-> longContainer.specifyType(registryOpType)).collect(Collectors.toList())) {
+    public void calcApplicationRt(String applicationName, String 
registryOpType, Long responseTime) {
+        for (LongContainer container : 
appRtStats.stream().filter(longContainer -> 
longContainer.specifyType(registryOpType)).collect(Collectors.toList())) {
             Number current = (Number) 
ConcurrentHashMapUtils.computeIfAbsent(container, applicationName, 
container.getInitFunc());
             container.getConsumerFunc().accept(responseTime, current);
         }
     }
 
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void calcServiceKeyRt(String applicationName, String serviceKey, 
String registryOpType, Long responseTime) {
+        for (LongContainer container : 
serviceRtStats.stream().filter(longContainer -> 
longContainer.specifyType(registryOpType)).collect(Collectors.toList())) {
+            Number current = (Number) 
ConcurrentHashMapUtils.computeIfAbsent(container, applicationName + "_" + 
serviceKey, container.getInitFunc());
+            container.getConsumerFunc().accept(responseTime, current);
+        }
+    }
+
     @Override
     @SuppressWarnings({"rawtypes"})
     public List<GaugeMetricSample> exportNumMetrics() {
         List<GaugeMetricSample> list = new ArrayList<>();
-        for (RegistryEvent.Type type : numStats.keySet()) {
-            Map<String, AtomicLong> stringAtomicLongMap = numStats.get(type);
+        for (RegistryEvent.ApplicationType type : 
applicationNumStats.keySet()) {
+            Map<String, AtomicLong> stringAtomicLongMap = 
applicationNumStats.get(type);
             for (String applicationName : stringAtomicLongMap.keySet()) {
                 list.add(convertToSample(applicationName, type, 
MetricsCategory.REGISTRY, stringAtomicLongMap.get(applicationName)));
             }
@@ -126,20 +160,26 @@ public class RegistryStatComposite implements 
MetricsExport {
     @Override
     @SuppressWarnings({"rawtypes"})
     public List<GaugeMetricSample> exportRtMetrics() {
-        List<GaugeMetricSample> list = new ArrayList<>();
+        List<GaugeMetricSample> result = new ArrayList<>();
+        doExportRt(result, appRtStats, ApplicationMetric::getTagsByName);
+        doExportRt(result, serviceRtStats, ApplicationMetric::getServiceTags);
+        return result;
+    }
+
+    @SuppressWarnings({"rawtypes"})
+    private void doExportRt(List<GaugeMetricSample> list, List<LongContainer<? 
extends Number>> rtStats, Function<String, Map<String, String>> tagNameFunc) {
         for (LongContainer<? extends Number> rtContainer : rtStats) {
             MetricsKeyWrapper metricsKeyWrapper = 
rtContainer.getMetricsKeyWrapper();
             for (Map.Entry<String, ? extends Number> entry : 
rtContainer.entrySet()) {
-                list.add(new 
GaugeMetricSample<>(metricsKeyWrapper.targetKey(), 
metricsKeyWrapper.targetDesc(), 
ApplicationMetric.getTagsByName(entry.getKey()), MetricsCategory.RT, 
entry.getKey().intern(), value -> 
rtContainer.getValueSupplier().apply(value.intern())));
+                list.add(new 
GaugeMetricSample<>(metricsKeyWrapper.targetKey(), 
metricsKeyWrapper.targetDesc(), tagNameFunc.apply(entry.getKey()), 
MetricsCategory.RT, entry.getKey().intern(), value -> 
rtContainer.getValueSupplier().apply(value.intern())));
             }
         }
-        return list;
     }
 
     @SuppressWarnings({"rawtypes"})
     public List<GaugeMetricSample> exportSkMetrics() {
         List<GaugeMetricSample> list = new ArrayList<>();
-        for (RegistryEvent.Type type : skStats.keySet()) {
+        for (RegistryEvent.ServiceType type : skStats.keySet()) {
             Map<ServiceKeyMetric, AtomicLong> stringAtomicLongMap = 
skStats.get(type);
             for (ServiceKeyMetric serviceKeyMetric : 
stringAtomicLongMap.keySet()) {
                 list.add(new GaugeMetricSample<>(type.getMetricsKey(), 
serviceKeyMetric.getTags(), MetricsCategory.REGISTRY, stringAtomicLongMap, 
value -> value.get(serviceKeyMetric).get()));
@@ -149,7 +189,7 @@ public class RegistryStatComposite implements MetricsExport 
{
     }
 
     @SuppressWarnings({"rawtypes"})
-    public GaugeMetricSample convertToSample(String applicationName, 
RegistryEvent.Type type, MetricsCategory category, AtomicLong targetNumber) {
+    public GaugeMetricSample convertToSample(String applicationName, 
RegistryEvent.ApplicationType type, MetricsCategory category, AtomicLong 
targetNumber) {
         return new GaugeMetricSample<>(type.getMetricsKey(), 
ApplicationMetric.getTagsByName(applicationName), category, targetNumber, 
AtomicLong::get);
     }
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsNotifyListener.java
 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsNotifyListener.java
index 3b5561cb1f..6dd7828faf 100644
--- 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsNotifyListener.java
+++ 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsNotifyListener.java
@@ -38,13 +38,13 @@ public class MetricsNotifyListener implements 
MetricsLifeListener<RegistryEvent.
 
     @Override
     public void onEvent(RegistryEvent.MetricsNotifyEvent event) {
-        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.Type.N_TOTAL);
+        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.ApplicationType.N_TOTAL);
     }
 
     @Override
     public void onEventFinish(RegistryEvent.MetricsNotifyEvent event) {
-        event.getCollector().setNum(RegistryEvent.Type.N_LAST_NUM, 
event.getSource().getApplicationName(), event.getLastNotifyNum());
-        event.getCollector().addRT(event.getSource().getApplicationName(), 
OP_TYPE_NOTIFY, event.getTimePair().calc());
+        event.getCollector().setNum(RegistryEvent.ServiceType.N_LAST_NUM, 
event.getSource().getApplicationName(), event.getLastNotifyNum());
+        
event.getCollector().addApplicationRT(event.getSource().getApplicationName(), 
OP_TYPE_NOTIFY, event.getTimePair().calc());
     }
 
     @Override
diff --git 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsRegisterListener.java
 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsRegisterListener.java
index f3c6352fcf..8fbe835a37 100644
--- 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsRegisterListener.java
+++ 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsRegisterListener.java
@@ -22,31 +22,31 @@ import 
org.apache.dubbo.metrics.listener.MetricsLifeListener;
 
 import static 
org.apache.dubbo.metrics.registry.collector.stat.RegistryStatComposite.OP_TYPE_REGISTER;
 
-public class MetricsRegisterListener implements 
MetricsLifeListener<RegistryEvent.MetricsRegisterEvent> {
+public class MetricsRegisterListener implements 
MetricsLifeListener<RegistryEvent.MetricsApplicationRegisterEvent> {
 
 
     @Override
     public boolean isSupport(MetricsEvent event) {
-        return event instanceof RegistryEvent.MetricsRegisterEvent;
+        return event instanceof RegistryEvent.MetricsApplicationRegisterEvent;
     }
 
     @Override
-    public void onEvent(RegistryEvent.MetricsRegisterEvent event) {
+    public void onEvent(RegistryEvent.MetricsApplicationRegisterEvent event) {
         if (!event.isAvailable()) {
             return;
         }
-        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.Type.R_TOTAL);
+        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.ApplicationType.R_TOTAL);
     }
 
     @Override
-    public void onEventFinish(RegistryEvent.MetricsRegisterEvent event) {
-        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.Type.R_SUCCEED);
-        event.getCollector().addRT(event.getSource().getApplicationName(), 
OP_TYPE_REGISTER, event.getTimePair().calc());
+    public void onEventFinish(RegistryEvent.MetricsApplicationRegisterEvent 
event) {
+        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.ApplicationType.R_SUCCEED);
+        
event.getCollector().addApplicationRT(event.getSource().getApplicationName(), 
OP_TYPE_REGISTER, event.getTimePair().calc());
     }
 
     @Override
-    public void onEventError(RegistryEvent.MetricsRegisterEvent event) {
-        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.Type.R_FAILED);
-        event.getCollector().addRT(event.getSource().getApplicationName(), 
OP_TYPE_REGISTER, event.getTimePair().calc());
+    public void onEventError(RegistryEvent.MetricsApplicationRegisterEvent 
event) {
+        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.ApplicationType.R_FAILED);
+        
event.getCollector().addApplicationRT(event.getSource().getApplicationName(), 
OP_TYPE_REGISTER, event.getTimePair().calc());
     }
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsServiceRegisterListener.java
 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsServiceRegisterListener.java
new file mode 100644
index 0000000000..e99ce7a75d
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsServiceRegisterListener.java
@@ -0,0 +1,51 @@
+/*
+ * 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.dubbo.metrics.registry.event;
+
+import org.apache.dubbo.metrics.event.MetricsEvent;
+import org.apache.dubbo.metrics.listener.MetricsLifeListener;
+
+import static 
org.apache.dubbo.metrics.registry.collector.stat.RegistryStatComposite.OP_TYPE_REGISTER_SERVICE;
+
+public class MetricsServiceRegisterListener implements 
MetricsLifeListener<RegistryEvent.MetricsServiceRegisterEvent> {
+
+    @Override
+    public boolean isSupport(MetricsEvent event) {
+        return event instanceof RegistryEvent.MetricsServiceRegisterEvent;
+    }
+
+    @Override
+    public void onEvent(RegistryEvent.MetricsServiceRegisterEvent event) {
+        if (!event.isAvailable()) {
+            return;
+        }
+        
event.getCollector().incrementServiceKey(event.getSource().getApplicationName(),
 event.getServiceKey(), RegistryEvent.ServiceType.R_SERVICE_TOTAL, 
event.getSize());
+    }
+
+    @Override
+    public void onEventFinish(RegistryEvent.MetricsServiceRegisterEvent event) 
{
+        
event.getCollector().incrementServiceKey(event.getSource().getApplicationName(),
 event.getServiceKey(), RegistryEvent.ServiceType.R_SERVICE_SUCCEED, 
event.getSize());
+        
event.getCollector().addServiceKeyRT(event.getSource().getApplicationName(), 
event.getServiceKey(), OP_TYPE_REGISTER_SERVICE, event.getTimePair().calc());
+    }
+
+    @Override
+    public void onEventError(RegistryEvent.MetricsServiceRegisterEvent event) {
+        
event.getCollector().incrementServiceKey(event.getSource().getApplicationName(),
 event.getServiceKey(), RegistryEvent.ServiceType.R_SERVICE_FAILED, 
event.getSize());
+        
event.getCollector().addApplicationRT(event.getSource().getApplicationName(), 
OP_TYPE_REGISTER_SERVICE, event.getTimePair().calc());
+    }
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsServiceSubscribeListener.java
 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsServiceSubscribeListener.java
new file mode 100644
index 0000000000..02062016dd
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsServiceSubscribeListener.java
@@ -0,0 +1,52 @@
+/*
+ * 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.dubbo.metrics.registry.event;
+
+import org.apache.dubbo.metrics.event.MetricsEvent;
+import org.apache.dubbo.metrics.listener.MetricsLifeListener;
+
+import static 
org.apache.dubbo.metrics.registry.collector.stat.RegistryStatComposite.OP_TYPE_SUBSCRIBE_SERVICE;
+
+public class MetricsServiceSubscribeListener implements 
MetricsLifeListener<RegistryEvent.MetricsServiceSubscribeEvent> {
+
+    @Override
+    public boolean isSupport(MetricsEvent event) {
+        return event instanceof RegistryEvent.MetricsServiceSubscribeEvent;
+    }
+
+    @Override
+    public void onEvent(RegistryEvent.MetricsServiceSubscribeEvent event) {
+        if (!event.isAvailable()) {
+            return;
+        }
+        
event.getCollector().incrementServiceKey(event.getSource().getApplicationName(),
 event.getUniqueServiceName(), RegistryEvent.ServiceType.S_SERVICE_TOTAL, 1);
+    }
+
+    @Override
+    public void onEventFinish(RegistryEvent.MetricsServiceSubscribeEvent 
event) {
+        
event.getCollector().incrementServiceKey(event.getSource().getApplicationName(),
 event.getUniqueServiceName(), RegistryEvent.ServiceType.S_SERVICE_SUCCEED, 1);
+        
event.getCollector().addApplicationRT(event.getSource().getApplicationName(), 
OP_TYPE_SUBSCRIBE_SERVICE, event.getTimePair().calc());
+    }
+
+    @Override
+    public void onEventError(RegistryEvent.MetricsServiceSubscribeEvent event) 
{
+        
event.getCollector().incrementServiceKey(event.getSource().getApplicationName(),
 event.getUniqueServiceName(), RegistryEvent.ServiceType.S_SERVICE_FAILED, 1);
+        
event.getCollector().addApplicationRT(event.getSource().getApplicationName(), 
OP_TYPE_SUBSCRIBE_SERVICE, event.getTimePair().calc());
+    }
+
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsSubscribeListener.java
 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsSubscribeListener.java
index abfc5a0624..1caf41c489 100644
--- 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsSubscribeListener.java
+++ 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/MetricsSubscribeListener.java
@@ -34,19 +34,19 @@ public class MetricsSubscribeListener implements 
MetricsLifeListener<RegistryEve
         if (!event.isAvailable()) {
             return;
         }
-        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.Type.S_TOTAL);
+        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.ApplicationType.S_TOTAL);
     }
 
     @Override
     public void onEventFinish(RegistryEvent.MetricsSubscribeEvent event) {
-        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.Type.S_SUCCEED);
-        event.getCollector().addRT(event.getSource().getApplicationName(), 
OP_TYPE_SUBSCRIBE, event.getTimePair().calc());
+        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.ApplicationType.S_SUCCEED);
+        
event.getCollector().addApplicationRT(event.getSource().getApplicationName(), 
OP_TYPE_SUBSCRIBE, event.getTimePair().calc());
     }
 
     @Override
     public void onEventError(RegistryEvent.MetricsSubscribeEvent event) {
-        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.Type.S_FAILED);
-        event.getCollector().addRT(event.getSource().getApplicationName(), 
OP_TYPE_SUBSCRIBE, event.getTimePair().calc());
+        event.getCollector().increment(event.getSource().getApplicationName(), 
RegistryEvent.ApplicationType.S_FAILED);
+        
event.getCollector().addApplicationRT(event.getSource().getApplicationName(), 
OP_TYPE_SUBSCRIBE, event.getTimePair().calc());
     }
 
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryEvent.java
 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryEvent.java
index c13eb2310d..5fb27ab31d 100644
--- 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryEvent.java
+++ 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryEvent.java
@@ -58,7 +58,7 @@ public class RegistryEvent extends MetricsEvent implements 
TimeCounter {
         return timePair;
     }
 
-    public enum Type {
+    public enum ApplicationType {
         R_TOTAL(MetricsKey.REGISTER_METRIC_REQUESTS),
         R_SUCCEED(MetricsKey.REGISTER_METRIC_REQUESTS_SUCCEED),
         R_FAILED(MetricsKey.REGISTER_METRIC_REQUESTS_FAILED),
@@ -74,19 +74,52 @@ public class RegistryEvent extends MetricsEvent implements 
TimeCounter {
         D_RECOVER_DISABLE(MetricsKey.DIRECTORY_METRIC_NUM_RECOVER_DISABLE),
 
         N_TOTAL(MetricsKey.NOTIFY_METRIC_REQUESTS),
-        N_LAST_NUM(MetricsKey.NOTIFY_METRIC_NUM_LAST),
         ;
 
+        private final MetricsKey metricsKey;
+        private final boolean isIncrement;
+
+
+        ApplicationType(MetricsKey metricsKey) {
+            this(metricsKey, true);
+        }
+
+        ApplicationType(MetricsKey metricsKey, boolean isIncrement) {
+            this.metricsKey = metricsKey;
+            this.isIncrement = isIncrement;
+        }
+
+        public MetricsKey getMetricsKey() {
+            return metricsKey;
+        }
+
+        public boolean isIncrement() {
+            return isIncrement;
+        }
+    }
+
+    public enum ServiceType {
+
+        N_LAST_NUM(MetricsKey.NOTIFY_METRIC_NUM_LAST),
+
+        R_SERVICE_TOTAL(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS),
+        R_SERVICE_SUCCEED(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED),
+        R_SERVICE_FAILED(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_FAILED),
+
+        S_SERVICE_TOTAL(MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM),
+        S_SERVICE_SUCCEED(MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED),
+        S_SERVICE_FAILED(MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_FAILED),
+        ;
 
         private final MetricsKey metricsKey;
         private final boolean isIncrement;
 
 
-        Type(MetricsKey metricsKey) {
+        ServiceType(MetricsKey metricsKey) {
             this(metricsKey, true);
         }
 
-        Type(MetricsKey metricsKey, boolean isIncrement) {
+        ServiceType(MetricsKey metricsKey, boolean isIncrement) {
             this.metricsKey = metricsKey;
             this.isIncrement = isIncrement;
         }
@@ -100,9 +133,9 @@ public class RegistryEvent extends MetricsEvent implements 
TimeCounter {
         }
     }
 
-    public static class MetricsRegisterEvent extends RegistryEvent {
+    public static class MetricsApplicationRegisterEvent extends RegistryEvent {
 
-        public MetricsRegisterEvent(ApplicationModel applicationModel, 
TimePair timePair) {
+        public MetricsApplicationRegisterEvent(ApplicationModel 
applicationModel, TimePair timePair) {
             super(applicationModel, timePair);
         }
 
@@ -132,20 +165,20 @@ public class RegistryEvent extends MetricsEvent 
implements TimeCounter {
 
     public static class MetricsDirectoryEvent extends RegistryEvent {
 
-        private final RegistryEvent.Type type;
+        private final ApplicationType type;
         private final int size;
 
-        public MetricsDirectoryEvent(ApplicationModel applicationModel, 
RegistryEvent.Type type) {
+        public MetricsDirectoryEvent(ApplicationModel applicationModel, 
ApplicationType type) {
             this(applicationModel, type, 1);
         }
 
-        public MetricsDirectoryEvent(ApplicationModel applicationModel, 
RegistryEvent.Type type, int size) {
+        public MetricsDirectoryEvent(ApplicationModel applicationModel, 
ApplicationType type, int size) {
             super(applicationModel, TimePair.empty());
             this.type = type;
             this.size = size;
         }
 
-        public RegistryEvent.Type getType() {
+        public ApplicationType getType() {
             return type;
         }
 
@@ -153,4 +186,38 @@ public class RegistryEvent extends MetricsEvent implements 
TimeCounter {
             return size;
         }
     }
+
+    public static class MetricsServiceRegisterEvent extends RegistryEvent {
+
+        private final int size;
+        private final String serviceKey;
+
+        public MetricsServiceRegisterEvent(ApplicationModel applicationModel, 
TimePair timePair, String serviceKey, int size) {
+            super(applicationModel, timePair);
+            this.size = size;
+            this.serviceKey = serviceKey;
+        }
+
+        public int getSize() {
+            return size;
+        }
+
+        public String getServiceKey() {
+            return serviceKey;
+        }
+    }
+
+    public static class MetricsServiceSubscribeEvent extends RegistryEvent {
+
+        private final String uniqueServiceName;
+
+        public MetricsServiceSubscribeEvent(ApplicationModel applicationModel, 
TimePair timePair, String uniqueServiceName) {
+            super(applicationModel, timePair);
+            this.uniqueServiceName = uniqueServiceName;
+        }
+
+        public String getUniqueServiceName() {
+            return uniqueServiceName;
+        }
+    }
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryMetricsEventMulticaster.java
 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryMetricsEventMulticaster.java
index 566607efdb..3ad78a26c8 100644
--- 
a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryMetricsEventMulticaster.java
+++ 
b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryMetricsEventMulticaster.java
@@ -26,6 +26,8 @@ public final class RegistryMetricsEventMulticaster extends 
SimpleMetricsEventMul
         super.addListener(new MetricsSubscribeListener());
         super.addListener(new MetricsNotifyListener());
         super.addListener(new MetricsDirectoryListener());
+        super.addListener(new MetricsServiceRegisterListener());
+        super.addListener(new MetricsServiceSubscribeListener());
 
         setAvailable();
     }
diff --git 
a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsCollectorTest.java
 
b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsCollectorTest.java
index 6fee8f039a..7b78456f2b 100644
--- 
a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsCollectorTest.java
+++ 
b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsCollectorTest.java
@@ -69,24 +69,24 @@ class RegistryMetricsCollectorTest {
         RegistryMetricsCollector collector = 
applicationModel.getBeanFactory().getOrRegisterBean(RegistryMetricsCollector.class);
         collector.setCollectEnabled(true);
 
-        eventMulticaster.publishEvent(new 
RegistryEvent.MetricsRegisterEvent(applicationModel, timePair));
+        eventMulticaster.publishEvent(new 
RegistryEvent.MetricsApplicationRegisterEvent(applicationModel, timePair));
         List<MetricSample> metricSamples = collector.collect();
 
         // push success +1
         Assertions.assertEquals(1, metricSamples.size());
         Assertions.assertTrue(metricSamples.get(0) instanceof 
GaugeMetricSample);
 
-        eventMulticaster.publishFinishEvent(new 
RegistryEvent.MetricsRegisterEvent(applicationModel, timePair));
+        eventMulticaster.publishFinishEvent(new 
RegistryEvent.MetricsApplicationRegisterEvent(applicationModel, timePair));
         // push finish rt +1
         metricSamples = collector.collect();
         //num(total+success) + rt(5) = 7
         Assertions.assertEquals(7, metricSamples.size());
         long c1 = timePair.calc();
         TimePair lastTimePair = TimePair.start();
-        eventMulticaster.publishEvent(new 
RegistryEvent.MetricsRegisterEvent(applicationModel, lastTimePair));
+        eventMulticaster.publishEvent(new 
RegistryEvent.MetricsApplicationRegisterEvent(applicationModel, lastTimePair));
         Thread.sleep(50);
         // push error rt +1
-        eventMulticaster.publishErrorEvent(new 
RegistryEvent.MetricsRegisterEvent(applicationModel, lastTimePair));
+        eventMulticaster.publishErrorEvent(new 
RegistryEvent.MetricsApplicationRegisterEvent(applicationModel, lastTimePair));
         long c2 = lastTimePair.calc();
         metricSamples = collector.collect();
 
diff --git 
a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsSampleTest.java
 
b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsSampleTest.java
index 759b4dae31..27b7a4f736 100644
--- 
a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsSampleTest.java
+++ 
b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsSampleTest.java
@@ -65,8 +65,8 @@ class RegistryMetricsSampleTest {
         RegistryMetricsCollector collector = new 
RegistryMetricsCollector(applicationModel);
         collector.setCollectEnabled(true);
         String applicationName = applicationModel.getApplicationName();
-        collector.addRT(applicationName, 
RegistryStatComposite.OP_TYPE_REGISTER, 10L);
-        collector.addRT(applicationName, 
RegistryStatComposite.OP_TYPE_REGISTER, 0L);
+        collector.addApplicationRT(applicationName, 
RegistryStatComposite.OP_TYPE_REGISTER, 10L);
+        collector.addApplicationRT(applicationName, 
RegistryStatComposite.OP_TYPE_REGISTER, 0L);
 
         List<MetricSample> samples = collector.collect();
         for (MetricSample sample : samples) {
@@ -89,7 +89,7 @@ class RegistryMetricsSampleTest {
         RegistryMetricsCollector collector = new 
RegistryMetricsCollector(applicationModel);
         collector.setCollectEnabled(true);
         String applicationName = applicationModel.getApplicationName();
-        collector.increment(applicationName,RegistryEvent.Type.R_TOTAL);
+        collector.increment(applicationName, 
RegistryEvent.ApplicationType.R_TOTAL);
     }
 
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryStatCompositeTest.java
 
b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryStatCompositeTest.java
index 9829809243..7d4753aa1b 100644
--- 
a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryStatCompositeTest.java
+++ 
b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryStatCompositeTest.java
@@ -36,12 +36,12 @@ public class RegistryStatCompositeTest {
     @Test
     void testInit() {
         RegistryStatComposite statComposite = new RegistryStatComposite();
-        Assertions.assertEquals(statComposite.numStats.size(), 
RegistryEvent.Type.values().length);
+        Assertions.assertEquals(statComposite.applicationNumStats.size(), 
RegistryEvent.ApplicationType.values().length);
         //(rt)5 * (register,subscribe,notify)3
-        Assertions.assertEquals(5 * 3, statComposite.rtStats.size());
-        statComposite.numStats.values().forEach((v ->
+        Assertions.assertEquals(5 * 3, statComposite.appRtStats.size());
+        statComposite.applicationNumStats.values().forEach((v ->
             Assertions.assertEquals(v, new ConcurrentHashMap<>())));
-        statComposite.rtStats.forEach(rtContainer ->
+        statComposite.appRtStats.forEach(rtContainer ->
         {
             for (Map.Entry<String, ? extends Number> entry : 
rtContainer.entrySet()) {
                 Assertions.assertEquals(0L, 
rtContainer.getValueSupplier().apply(entry.getKey()));
@@ -52,16 +52,16 @@ public class RegistryStatCompositeTest {
     @Test
     void testIncrement() {
         RegistryStatComposite statComposite = new RegistryStatComposite();
-        statComposite.increment(RegistryEvent.Type.R_TOTAL, applicationName);
-        Assertions.assertEquals(1L, 
statComposite.numStats.get(RegistryEvent.Type.R_TOTAL).get(applicationName).get());
+        statComposite.increment(RegistryEvent.ApplicationType.R_TOTAL, 
applicationName);
+        Assertions.assertEquals(1L, 
statComposite.applicationNumStats.get(RegistryEvent.ApplicationType.R_TOTAL).get(applicationName).get());
     }
 
     @Test
     void testCalcRt() {
         RegistryStatComposite statComposite = new RegistryStatComposite();
-        statComposite.calcRt(applicationName, OP_TYPE_NOTIFY, 10L);
-        
Assertions.assertTrue(statComposite.rtStats.stream().anyMatch(longContainer -> 
longContainer.specifyType(OP_TYPE_NOTIFY)));
-        Optional<LongContainer<? extends Number>> subContainer = 
statComposite.rtStats.stream().filter(longContainer -> 
longContainer.specifyType(OP_TYPE_NOTIFY)).findFirst();
+        statComposite.calcApplicationRt(applicationName, OP_TYPE_NOTIFY, 10L);
+        
Assertions.assertTrue(statComposite.appRtStats.stream().anyMatch(longContainer 
-> longContainer.specifyType(OP_TYPE_NOTIFY)));
+        Optional<LongContainer<? extends Number>> subContainer = 
statComposite.appRtStats.stream().filter(longContainer -> 
longContainer.specifyType(OP_TYPE_NOTIFY)).findFirst();
         subContainer.ifPresent(v -> Assertions.assertEquals(10L, 
v.get(applicationName).longValue()));
     }
 }
diff --git 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java
 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java
index 5cb52f08dd..0714987b38 100644
--- 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java
+++ 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java
@@ -25,6 +25,9 @@ import org.apache.dubbo.metadata.AbstractServiceNameMapping;
 import org.apache.dubbo.metadata.MappingChangedEvent;
 import org.apache.dubbo.metadata.MappingListener;
 import org.apache.dubbo.metadata.ServiceNameMapping;
+import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster;
+import org.apache.dubbo.metrics.model.TimePair;
+import org.apache.dubbo.metrics.registry.event.RegistryEvent;
 import org.apache.dubbo.registry.NotifyListener;
 import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent;
 import 
org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;
@@ -33,6 +36,7 @@ import org.apache.dubbo.rpc.model.ApplicationModel;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -322,13 +326,25 @@ public class ServiceDiscoveryRegistry extends 
FailbackRegistry {
                 serviceListeners.put(serviceNamesKey, 
serviceInstancesChangedListener);
             }
 
+            ApplicationModel applicationModel = 
Optional.ofNullable(url.getApplicationModel()).orElse(ApplicationModel.defaultModel())
 ;
+            GlobalMetricsEventMulticaster eventMulticaster = 
applicationModel.getBeanFactory().getBean(GlobalMetricsEventMulticaster.class);
+            TimePair timePair = TimePair.start();
+
+            eventMulticaster.publishEvent(new 
RegistryEvent.MetricsServiceSubscribeEvent(applicationModel, timePair, 
serviceKey));
             if (!serviceInstancesChangedListener.isDestroyed()) {
                 listener.addServiceListener(serviceInstancesChangedListener);
                 serviceInstancesChangedListener.addListenerAndNotify(url, 
listener);
-                
serviceDiscovery.addServiceInstancesChangedListener(serviceInstancesChangedListener);
+                try {
+                    
serviceDiscovery.addServiceInstancesChangedListener(serviceInstancesChangedListener);
+                } catch (Throwable t) {
+                    eventMulticaster.publishErrorEvent(new 
RegistryEvent.MetricsServiceSubscribeEvent(applicationModel, timePair, 
serviceKey));
+                    throw t;
+                }
+                eventMulticaster.publishFinishEvent(new 
RegistryEvent.MetricsServiceSubscribeEvent(applicationModel, timePair, 
serviceKey));
             } else {
                 logger.info(String.format("Listener of %s has been destroyed 
by another thread.", serviceNamesKey));
                 serviceListeners.remove(serviceNamesKey);
+                eventMulticaster.publishErrorEvent(new 
RegistryEvent.MetricsSubscribeEvent(applicationModel, timePair));
             }
         } finally {
             appSubscriptionLock.unlock();

Reply via email to