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 671e0f8bb9 Observability task: metadata center (#11593)
671e0f8bb9 is described below

commit 671e0f8bb9b7ebb447314660eea062869283888f
Author: wxbty <[email protected]>
AuthorDate: Wed Feb 22 20:44:58 2023 +0800

    Observability task: metadata center (#11593)
    
    * init metadata
    
    * add pom
    
    * add licence
    
    * add licence
    
    * remove unuse pom
    
    * remove unuse pom
    
    * remove unuse pom
    
    * fix test
    
    * fix test
    
    * fix test
    
    * fix pom
    
    * use applicationModel
    
    * remove unuse
    
    * add test
    
    * add push testcase
    
    * add test case
    
    * add test case
    
    * add testcase
    
    * rename
    
    * opt
    
    * debug
    
    * fix testcase
    
    * add pom
    
    ---------
    
    Co-authored-by: x-shadow-man <[email protected]>
---
 .../org/apache/dubbo/config/MetricsConfig.java     |  19 +-
 dubbo-config/dubbo-config-api/pom.xml              |   6 +
 .../config/deploy/DefaultApplicationDeployer.java  |   2 +-
 dubbo-distribution/dubbo-all/pom.xml               |   8 +
 dubbo-distribution/dubbo-bom/pom.xml               |   5 +
 .../collector/ApplicationMetricsCollector.java     |   8 +-
 .../dubbo/metrics/collector/MetricsCollector.java  |   9 +-
 .../event/GlobalMetricsEventMulticaster.java       |  12 +-
 .../metrics/listener/MetricsLifeListener.java      |   6 +-
 .../dubbo/metrics/listener/MetricsListener.java    |   3 +-
 .../org/apache/dubbo/metrics/model/MetricsKey.java |  26 ++-
 .../dubbo/metrics/model/MetricsKeyWrapper.java     |   4 +-
 .../event/SimpleMetricsEventMulticasterTest.java   |   8 +-
 .../metrics/MetricsScopeModelInitializer.java      |   2 +-
 dubbo-metrics/{ => dubbo-metrics-metadata}/pom.xml |  17 +-
 .../collector/MetadataMetricsCollector.java        | 111 +++++++++++
 .../collector/stat/MetadataStatComposite.java      | 212 +++++++++++++++++++++
 .../metrics/metadata/event/MetadataEvent.java      | 109 +++++++++++
 .../event/MetadataMetricsEventMulticaster.java}    |  23 +--
 .../metadata/event/MetricsPushListener.java        |  49 +++++
 .../metadata/event/MetricsSubscribeListener.java   |  49 +++++
 ...apache.dubbo.metrics.collector.MetricsCollector |   1 +
 .../collector/MetadataMetricsCollectorTest.java    | 168 ++++++++++++++++
 dubbo-metrics/pom.xml                              |   1 +
 .../META-INF/native-image/reflect-config.json      |  12 +-
 dubbo-registry/dubbo-registry-api/pom.xml          |  18 ++
 .../registry/client/AbstractServiceDiscovery.java  |  39 +++-
 dubbo-test/dubbo-dependencies-all/pom.xml          |   4 +
 28 files changed, 861 insertions(+), 70 deletions(-)

diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java 
b/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java
index 8811d5d612..1b8340138b 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java
@@ -16,9 +16,6 @@
  */
 package org.apache.dubbo.config;
 
-import java.util.HashMap;
-import java.util.Map;
-
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.UrlUtils;
 import org.apache.dubbo.config.nested.AggregationConfig;
@@ -26,6 +23,9 @@ import org.apache.dubbo.config.nested.PrometheusConfig;
 import org.apache.dubbo.config.support.Nested;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * MetricsConfig
  */
@@ -40,6 +40,11 @@ public class MetricsConfig extends AbstractConfig {
      */
     private Boolean enableJvmMetrics;
 
+    /**
+     * Enable jvm metrics when collecting.
+     */
+    private Boolean enableMetadataMetrics;
+
     /**
      * @deprecated After metrics config is refactored.
      * This parameter should no longer use and will be deleted in the future.
@@ -137,5 +142,13 @@ public class MetricsConfig extends AbstractConfig {
     public void setExportServicePort(Integer exportServicePort) {
         this.exportServicePort = exportServicePort;
     }
+
+    public Boolean getEnableMetadataMetrics() {
+        return enableMetadataMetrics;
+    }
+
+    public void setEnableMetadataMetrics(Boolean enableMetadataMetrics) {
+        this.enableMetadataMetrics = enableMetadataMetrics;
+    }
 }
 
diff --git a/dubbo-config/dubbo-config-api/pom.xml 
b/dubbo-config/dubbo-config-api/pom.xml
index c863389111..2ba42d26a3 100644
--- a/dubbo-config/dubbo-config-api/pom.xml
+++ b/dubbo-config/dubbo-config-api/pom.xml
@@ -48,6 +48,12 @@
             <version>${project.parent.version}</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-metrics-metadata</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+
         <dependency>
             <groupId>org.apache.dubbo</groupId>
             <artifactId>dubbo-monitor-api</artifactId>
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 e5853a9f4c..c526864ab4 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
@@ -359,7 +359,7 @@ public class DefaultApplicationDeployer extends 
AbstractDeployer<ApplicationMode
 
     private void initMetricsReporter() {
         DefaultMetricsCollector collector =
-            
applicationModel.getFrameworkModel().getBeanFactory().getBean(DefaultMetricsCollector.class);
+            
applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
         MetricsConfig metricsConfig = configManager.getMetrics().orElse(null);
         // TODO compatible with old usage of metrics, remove protocol check 
after new metrics is ready for use.
         if (metricsConfig != null && 
PROTOCOL_PROMETHEUS.equals(metricsConfig.getProtocol())) {
diff --git a/dubbo-distribution/dubbo-all/pom.xml 
b/dubbo-distribution/dubbo-all/pom.xml
index 23b1192686..7e96659152 100644
--- a/dubbo-distribution/dubbo-all/pom.xml
+++ b/dubbo-distribution/dubbo-all/pom.xml
@@ -197,6 +197,13 @@
             <scope>compile</scope>
             <optional>true</optional>
         </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-metrics-metadata</artifactId>
+            <version>${project.version}</version>
+            <scope>compile</scope>
+            <optional>true</optional>
+        </dependency>
 
         <!-- monitor -->
         <dependency>
@@ -495,6 +502,7 @@
                                     
<include>org.apache.dubbo:dubbo-metadata-report-zookeeper</include>
                                     
<include>org.apache.dubbo:dubbo-metrics-api</include>
                                     
<include>org.apache.dubbo:dubbo-metrics-default</include>
+                                    
<include>org.apache.dubbo:dubbo-metrics-metadata</include>
                                     
<include>org.apache.dubbo:dubbo-metrics-prometheus</include>
                                     
<include>org.apache.dubbo:dubbo-monitor-api</include>
                                     
<include>org.apache.dubbo:dubbo-monitor-default</include>
diff --git a/dubbo-distribution/dubbo-bom/pom.xml 
b/dubbo-distribution/dubbo-bom/pom.xml
index 4b22ec55f9..42b26038cd 100644
--- a/dubbo-distribution/dubbo-bom/pom.xml
+++ b/dubbo-distribution/dubbo-bom/pom.xml
@@ -240,6 +240,11 @@
                 <artifactId>dubbo-metrics-prometheus</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.dubbo</groupId>
+                <artifactId>dubbo-metrics-metadata</artifactId>
+                <version>${project.version}</version>
+            </dependency>
 
             <!-- monitor -->
             <dependency>
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 b437561a7b..c1dc63e5b2 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
@@ -17,18 +17,18 @@
 
 package org.apache.dubbo.metrics.collector;
 
+import org.apache.dubbo.metrics.event.MetricsEvent;
+
 /**
  * Application-level collector.
  * registration center, configuration center and other scenarios
  *
  * @Params <T>  metrics type
  */
-public interface ApplicationMetricsCollector<T> extends MetricsCollector {
+public interface ApplicationMetricsCollector<T, E extends MetricsEvent> 
extends MetricsCollector<E> {
 
     void increment(String applicationName, T type);
 
-    void decrease(String applicationName, T type);
-
-    void addRT(String applicationName, Long responseTime);
+    void addRT(String applicationName, String registryOpType, Long 
responseTime);
 }
 
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/MetricsCollector.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/MetricsCollector.java
index d722f77547..3436d4f829 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/MetricsCollector.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/MetricsCollector.java
@@ -19,7 +19,7 @@ package org.apache.dubbo.metrics.collector;
 
 import org.apache.dubbo.common.extension.SPI;
 import org.apache.dubbo.metrics.event.MetricsEvent;
-import org.apache.dubbo.metrics.listener.MetricsListener;
+import org.apache.dubbo.metrics.listener.MetricsLifeListener;
 import org.apache.dubbo.metrics.model.sample.MetricSample;
 
 import java.util.List;
@@ -29,11 +29,12 @@ import java.util.List;
  * An interface of collector to collect framework internal metrics.
  */
 @SPI
-public interface MetricsCollector extends MetricsListener {
+public interface MetricsCollector<E extends MetricsEvent> extends 
MetricsLifeListener<E> {
 
     default boolean isCollectEnabled() {
         return false;
     }
+
     /**
      * Collect metrics as {@link MetricSample}
      *
@@ -41,8 +42,4 @@ public interface MetricsCollector extends MetricsListener {
      */
     List<MetricSample> collect();
 
-    @Override
-    default void onEvent(MetricsEvent event) {
-
-    }
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/GlobalMetricsEventMulticaster.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/GlobalMetricsEventMulticaster.java
index b5d4effdfe..28f01d5c27 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/GlobalMetricsEventMulticaster.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/GlobalMetricsEventMulticaster.java
@@ -20,15 +20,19 @@ package org.apache.dubbo.metrics.event;
 import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.metrics.collector.MetricsCollector;
-import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.model.ApplicationModel;
 
 import java.util.List;
 
+/**
+ * Global spi event publisher
+ */
 public class GlobalMetricsEventMulticaster extends 
SimpleMetricsEventMulticaster {
 
-    public GlobalMetricsEventMulticaster(FrameworkModel frameworkModel) {
-        ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();
-        ExtensionLoader<MetricsCollector> extensionLoader = 
frameworkModel.getExtensionLoader(MetricsCollector.class);
+    @SuppressWarnings({"rawtypes"})
+    public GlobalMetricsEventMulticaster(ApplicationModel applicationModel) {
+        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
+        ExtensionLoader<MetricsCollector> extensionLoader = 
applicationModel.getExtensionLoader(MetricsCollector.class);
         if (extensionLoader != null) {
             List<MetricsCollector> customizeCollectors = extensionLoader
                 .getActivateExtensions();
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsLifeListener.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsLifeListener.java
index 80098f67bf..bee82056be 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsLifeListener.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsLifeListener.java
@@ -24,7 +24,9 @@ import org.apache.dubbo.metrics.event.MetricsEvent;
  */
 public interface MetricsLifeListener<E extends MetricsEvent> extends 
MetricsListener<E> {
 
-    void onEventFinish(E event);
+    default void onEventFinish(E event) {
+    }
 
-    void onEventError(E event);
+    default void onEventError(E event) {
+    }
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsListener.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsListener.java
index 058f583e94..64b4796af3 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsListener.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsListener.java
@@ -33,6 +33,7 @@ public interface MetricsListener<E extends MetricsEvent> {
      *
      * @param event BaseMetricsEvent
      */
-    void onEvent(E event);
+    default void onEvent(E event) {
+    }
 
 }
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 7649af788a..96c879c8dd 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
@@ -30,7 +30,6 @@ public enum MetricsKey {
     METRIC_REQUESTS_FAILED("dubbo.%s.requests.unknown.failed.total", "Unknown 
Failed Requests"),
     METRIC_REQUESTS_TOTAL_FAILED("dubbo.%s.requests.failed.total", "Total 
Failed Requests"),
 
-
     METRIC_REQUESTS_TOTAL_AGG("dubbo.%s.requests.total.aggregate", "Aggregated 
Total Requests"),
     METRIC_REQUESTS_SUCCEED_AGG("dubbo.%s.requests.succeed.aggregate", 
"Aggregated Succeed Requests"),
     METRIC_REQUESTS_FAILED_AGG("dubbo.%s.requests.failed.aggregate", 
"Aggregated Failed Requests"),
@@ -60,12 +59,25 @@ public enum MetricsKey {
     GENERIC_METRIC_RT_P99("dubbo.%s.rt.seconds.p99", "Response Time P99"),
     GENERIC_METRIC_RT_P95("dubbo.%s.rt.seconds.p95", "Response Time P95"),
 
-    THREAD_POOL_CORE_SIZE("dubbo.thread.pool.core.size","Thread Pool Core 
Size"),
-    THREAD_POOL_LARGEST_SIZE("dubbo.thread.pool.largest.size","Thread Pool 
Largest Size"),
-    THREAD_POOL_MAX_SIZE("dubbo.thread.pool.max.size","Thread Pool Max Size"),
-    THREAD_POOL_ACTIVE_SIZE("dubbo.thread.pool.active.size","Thread Pool 
Active Size"),
-    THREAD_POOL_THREAD_COUNT("dubbo.thread.pool.thread.count","Thread Pool 
Thread Count"),
-    THREAD_POOL_QUEUE_SIZE("dubbo.thread.pool.queue.size","Thread Pool Queue 
Size");
+    THREAD_POOL_CORE_SIZE("dubbo.thread.pool.core.size", "Thread Pool Core 
Size"),
+    THREAD_POOL_LARGEST_SIZE("dubbo.thread.pool.largest.size", "Thread Pool 
Largest Size"),
+    THREAD_POOL_MAX_SIZE("dubbo.thread.pool.max.size", "Thread Pool Max Size"),
+    THREAD_POOL_ACTIVE_SIZE("dubbo.thread.pool.active.size", "Thread Pool 
Active Size"),
+    THREAD_POOL_THREAD_COUNT("dubbo.thread.pool.thread.count", "Thread Pool 
Thread Count"),
+    THREAD_POOL_QUEUE_SIZE("dubbo.thread.pool.queue.size", "Thread Pool Queue 
Size"),
+
+    // metadata push metrics key
+    METADATA_PUSH_METRIC_NUM("dubbo.metadata.push.num.total", "Total Push 
Num"),
+    METADATA_PUSH_METRIC_NUM_SUCCEED("dubbo.metadata.push.num.succeed.total", 
"Succeed Push Num"),
+    METADATA_PUSH_METRIC_NUM_FAILED("dubbo.metadata.push.num.failed.total", 
"Failed Push Num"),
+
+    // metadata subscribe metrics key
+    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"),
+
+    // consumer metrics key
+    ;
 
     private final String name;
     private final String description;
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKeyWrapper.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKeyWrapper.java
index 0a0afc95e8..54b791e5a8 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKeyWrapper.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKeyWrapper.java
@@ -38,8 +38,8 @@ public class MetricsKeyWrapper {
         return metricsKey;
     }
 
-    public boolean isKey(MetricsKey metricsKey) {
-        return metricsKey == getMetricsKey();
+    public boolean isKey(MetricsKey metricsKey, String registryOpType) {
+        return metricsKey == getMetricsKey() && 
registryOpType.equals(getType());
     }
 
     public String targetKey() {
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticasterTest.java
 
b/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticasterTest.java
index de5314d803..15f6e66f23 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticasterTest.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/event/SimpleMetricsEventMulticasterTest.java
@@ -18,6 +18,7 @@
 package org.apache.dubbo.metrics.event;
 
 import org.apache.dubbo.metrics.listener.MetricsLifeListener;
+import org.apache.dubbo.metrics.listener.MetricsListener;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -32,7 +33,12 @@ public class SimpleMetricsEventMulticasterTest {
     public void setup() {
         eventMulticaster = new SimpleMetricsEventMulticaster();
         obj = new Object[]{new Object()};
-        eventMulticaster.addListener(event -> obj[0] = new Object());
+        eventMulticaster.addListener(new MetricsListener<MetricsEvent>() {
+            @Override
+            public void onEvent(MetricsEvent event) {
+                obj[0] = new Object();
+            }
+        });
         requestEvent = new RequestEvent(obj[0], MetricsEvent.Type.TOTAL);
 
     }
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsScopeModelInitializer.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsScopeModelInitializer.java
index 6f786b2c67..f8236f60d2 100644
--- 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsScopeModelInitializer.java
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsScopeModelInitializer.java
@@ -34,7 +34,7 @@ public class MetricsScopeModelInitializer implements 
ScopeModelInitializer {
 
     @Override
     public void initializeApplicationModel(ApplicationModel applicationModel) {
-        ScopeBeanFactory beanFactory = 
applicationModel.getFrameworkModel().getBeanFactory();
+        ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
         beanFactory.registerBean(DefaultMetricsCollector.class);
         beanFactory.registerBean(GlobalMetricsEventMulticaster.class);
     }
diff --git a/dubbo-metrics/pom.xml 
b/dubbo-metrics/dubbo-metrics-metadata/pom.xml
similarity index 80%
copy from dubbo-metrics/pom.xml
copy to dubbo-metrics/dubbo-metrics-metadata/pom.xml
index c504428498..f454e9558e 100644
--- a/dubbo-metrics/pom.xml
+++ b/dubbo-metrics/dubbo-metrics-metadata/pom.xml
@@ -13,35 +13,28 @@
   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.
-  -->
+-->
 <project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
     <modelVersion>4.0.0</modelVersion>
-    <modules>
-        <module>dubbo-metrics-api</module>
-        <module>dubbo-metrics-default</module>
-        <module>dubbo-metrics-prometheus</module>
-    </modules>
     <parent>
         <groupId>org.apache.dubbo</groupId>
-        <artifactId>dubbo-parent</artifactId>
+        <artifactId>dubbo-metrics</artifactId>
         <version>${revision}</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
-    <artifactId>dubbo-metrics</artifactId>
-    <packaging>pom</packaging>
+    <artifactId>dubbo-metrics-metadata</artifactId>
+    <packaging>jar</packaging>
     <name>${project.artifactId}</name>
     <description>The metrics module of dubbo project</description>
     <properties>
         <skip_maven_deploy>false</skip_maven_deploy>
     </properties>
-
     <dependencies>
         <dependency>
             <groupId>org.apache.dubbo</groupId>
-            <artifactId>dubbo-test-check</artifactId>
+            <artifactId>dubbo-metrics-api</artifactId>
             <version>${project.parent.version}</version>
-            <scope>test</scope>
         </dependency>
     </dependencies>
 </project>
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
new file mode 100644
index 0000000000..c9140a288c
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/collector/MetadataMetricsCollector.java
@@ -0,0 +1,111 @@
+/*
+ * 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.metadata.collector;
+
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.metrics.collector.ApplicationMetricsCollector;
+import org.apache.dubbo.metrics.collector.MetricsCollector;
+import org.apache.dubbo.metrics.event.MetricsEvent;
+import org.apache.dubbo.metrics.event.MetricsEventMulticaster;
+import org.apache.dubbo.metrics.metadata.collector.stat.MetadataStatComposite;
+import org.apache.dubbo.metrics.metadata.event.MetadataEvent;
+import org.apache.dubbo.metrics.metadata.event.MetadataMetricsEventMulticaster;
+import org.apache.dubbo.metrics.model.sample.MetricSample;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+
+/**
+ * Registry implementation of {@link MetricsCollector}
+ */
+@Activate
+public class MetadataMetricsCollector implements 
ApplicationMetricsCollector<MetadataEvent.Type, MetadataEvent> {
+
+    private Boolean collectEnabled = null;
+    private final MetadataStatComposite stats;
+    private final MetricsEventMulticaster metadataEventMulticaster;
+    private final ApplicationModel applicationModel;
+
+    public MetadataMetricsCollector(ApplicationModel applicationModel) {
+        this.stats = new MetadataStatComposite();
+        this.metadataEventMulticaster = new MetadataMetricsEventMulticaster();
+        this.applicationModel = applicationModel;
+    }
+
+    public void setCollectEnabled(Boolean collectEnabled) {
+        if (collectEnabled != null) {
+            this.collectEnabled = collectEnabled;
+        }
+    }
+
+    @Override
+    public boolean isCollectEnabled() {
+        if (collectEnabled == null) {
+            ConfigManager configManager = 
applicationModel.getApplicationConfigManager();
+            configManager.getMetrics().ifPresent(metricsConfig -> 
setCollectEnabled(metricsConfig.getEnableMetadataMetrics()));
+        }
+        return Optional.ofNullable(collectEnabled).orElse(false);
+    }
+
+    @Override
+    public void increment(String applicationName, MetadataEvent.Type 
registryType) {
+        this.stats.increment(registryType, applicationName);
+    }
+
+    @Override
+    public void addRT(String applicationName, String registryOpType, Long 
responseTime) {
+        stats.calcRt(applicationName, registryOpType, responseTime);
+    }
+
+    @Override
+    public List<MetricSample> collect() {
+        List<MetricSample> list = new ArrayList<>();
+        if (!isCollectEnabled()) {
+            return list;
+        }
+        list.addAll(stats.exportNumMetrics());
+        list.addAll(stats.exportRtMetrics());
+
+        return list;
+    }
+
+    @Override
+    public boolean isSupport(MetricsEvent event) {
+        return event instanceof MetadataEvent;
+    }
+
+    @Override
+    public void onEvent(MetadataEvent event) {
+        metadataEventMulticaster.publishEvent(event);
+    }
+
+
+    @Override
+    public void onEventFinish(MetadataEvent event) {
+        metadataEventMulticaster.publishFinishEvent(event);
+    }
+
+    @Override
+    public void onEventError(MetadataEvent event) {
+        metadataEventMulticaster.publishErrorEvent(event);
+    }
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/collector/stat/MetadataStatComposite.java
 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/collector/stat/MetadataStatComposite.java
new file mode 100644
index 0000000000..83cdbb855c
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/collector/stat/MetadataStatComposite.java
@@ -0,0 +1,212 @@
+/*
+ * 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.metadata.collector.stat;
+
+import org.apache.dubbo.common.utils.ConcurrentHashMapUtils;
+import org.apache.dubbo.metrics.collector.MetricsCollector;
+import org.apache.dubbo.metrics.model.ApplicationMetric;
+import org.apache.dubbo.metrics.model.MetricsCategory;
+import org.apache.dubbo.metrics.model.MetricsKey;
+import org.apache.dubbo.metrics.model.MetricsKeyWrapper;
+import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
+import org.apache.dubbo.metrics.metadata.event.MetadataEvent;
+import org.apache.dubbo.metrics.report.MetricsExport;
+
+import java.util.ArrayList;
+import java.util.List;
+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.BiConsumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+/**
+ * As a data aggregator, use internal data containers calculates and classifies
+ * the registry data collected by {@link MetricsCollector MetricsCollector}, 
and
+ * provides an {@link MetricsExport MetricsExport} interface for exporting 
standard output formats.
+ */
+public class MetadataStatComposite implements MetricsExport {
+
+
+    public Map<MetadataEvent.Type, Map<String, AtomicLong>> numStats = new 
ConcurrentHashMap<>();
+    public List<LongContainer<? extends Number>> rtStats = new ArrayList<>();
+    public static String OP_TYPE_PUSH = "push";
+    public static String OP_TYPE_SUBSCRIBE = "subscribe";
+
+    public MetadataStatComposite() {
+        for (MetadataEvent.Type type : MetadataEvent.Type.values()) {
+            numStats.put(type, new ConcurrentHashMap<>());
+        }
+
+        rtStats.addAll(initStats(OP_TYPE_PUSH));
+        rtStats.addAll(initStats(OP_TYPE_SUBSCRIBE));
+    }
+
+    private List<LongContainer<? extends Number>> initStats(String 
registryOpType) {
+        List<LongContainer<? extends Number>> singleRtStats = new 
ArrayList<>();
+        singleRtStats.add(new AtomicLongContainer(new 
MetricsKeyWrapper(registryOpType, MetricsKey.GENERIC_METRIC_RT_LAST)));
+        singleRtStats.add(new LongAccumulatorContainer(new 
MetricsKeyWrapper(registryOpType, MetricsKey.GENERIC_METRIC_RT_MIN), new 
LongAccumulator(Long::min, Long.MAX_VALUE)));
+        singleRtStats.add(new LongAccumulatorContainer(new 
MetricsKeyWrapper(registryOpType, MetricsKey.GENERIC_METRIC_RT_MAX), new 
LongAccumulator(Long::max, Long.MIN_VALUE)));
+        singleRtStats.add(new AtomicLongContainer(new 
MetricsKeyWrapper(registryOpType, MetricsKey.GENERIC_METRIC_RT_SUM), 
(responseTime, longAccumulator) -> longAccumulator.addAndGet(responseTime)));
+        // 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.GENERIC_METRIC_RT_AVG), (k, v) -> 
v.incrementAndGet());
+        avgContainer.setValueSupplier(applicationName -> {
+            LongContainer<? extends Number> totalContainer = 
rtStats.stream().filter(longContainer -> 
longContainer.isKeyWrapper(MetricsKey.GENERIC_METRIC_RT_SUM, 
registryOpType)).findFirst().get();
+            AtomicLong totalRtTimes = avgContainer.get(applicationName);
+            AtomicLong totalRtSum = (AtomicLong) 
totalContainer.get(applicationName);
+            return totalRtSum.get() / totalRtTimes.get();
+        });
+        singleRtStats.add(avgContainer);
+        return singleRtStats;
+    }
+
+    public void increment(MetadataEvent.Type type, String applicationName) {
+        if (!numStats.containsKey(type)) {
+            return;
+        }
+        numStats.get(type).computeIfAbsent(applicationName, k -> new 
AtomicLong(0L)).incrementAndGet();
+    }
+
+    @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())) {
+            Number current = (Number) 
ConcurrentHashMapUtils.computeIfAbsent(container, applicationName, 
container.getInitFunc());
+            container.getConsumerFunc().accept(responseTime, current);
+        }
+    }
+
+    @Override
+    public List<GaugeMetricSample> exportNumMetrics() {
+        List<GaugeMetricSample> list = new ArrayList<>();
+        for (MetadataEvent.Type type : numStats.keySet()) {
+            Map<String, AtomicLong> stringAtomicLongMap = numStats.get(type);
+            for (String applicationName : stringAtomicLongMap.keySet()) {
+                list.add(convertToSample(applicationName, type, 
MetricsCategory.REGISTRY, stringAtomicLongMap.get(applicationName)));
+            }
+        }
+        return list;
+    }
+
+    @Override
+    public List<GaugeMetricSample> exportRtMetrics() {
+        List<GaugeMetricSample> list = new ArrayList<>();
+        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, () -> 
rtContainer.getValueSupplier().apply(entry.getKey())));
+            }
+        }
+        return list;
+    }
+
+    public GaugeMetricSample convertToSample(String applicationName, 
MetadataEvent.Type type, MetricsCategory category, AtomicLong targetNumber) {
+        return new GaugeMetricSample(type.getMetricsKey(), 
ApplicationMetric.getTagsByName(applicationName), category, targetNumber::get);
+    }
+
+
+    /**
+     * Collect Number type data
+     *
+     * @param <NUMBER>
+     */
+    public static class LongContainer<NUMBER extends Number> extends 
ConcurrentHashMap<String, NUMBER> {
+
+        /**
+         * Provide the metric type name
+         */
+        private final MetricsKeyWrapper metricsKeyWrapper;
+        /**
+         * The initial value corresponding to the key is generally 0 of 
different data types
+         */
+        private final Function<String, NUMBER> initFunc;
+        /**
+         * Statistical data calculation function, which can be self-increment, 
self-decrement, or more complex avg function
+         */
+        private final BiConsumer<Long, NUMBER> consumerFunc;
+        /**
+         * Data output function required by  {@link GaugeMetricSample 
GaugeMetricSample}
+         */
+        private Function<String, Long> valueSupplier;
+
+
+        public LongContainer(MetricsKeyWrapper metricsKeyWrapper, 
Supplier<NUMBER> initFunc, BiConsumer<Long, NUMBER> consumerFunc) {
+            this.metricsKeyWrapper = metricsKeyWrapper;
+            this.initFunc = s -> initFunc.get();
+            this.consumerFunc = consumerFunc;
+            this.valueSupplier = k -> this.get(k).longValue();
+        }
+
+        public boolean specifyType(String type) {
+            return type.equals(getMetricsKeyWrapper().getType());
+        }
+
+        public MetricsKeyWrapper getMetricsKeyWrapper() {
+            return metricsKeyWrapper;
+        }
+
+        public boolean isKeyWrapper(MetricsKey metricsKey, String 
registryOpType) {
+            return metricsKeyWrapper.isKey(metricsKey,registryOpType);
+        }
+
+        public Function<String, NUMBER> getInitFunc() {
+            return initFunc;
+        }
+
+        public BiConsumer<Long, NUMBER> getConsumerFunc() {
+            return consumerFunc;
+        }
+
+        public Function<String, Long> getValueSupplier() {
+            return valueSupplier;
+        }
+
+        public void setValueSupplier(Function<String, Long> valueSupplier) {
+            this.valueSupplier = valueSupplier;
+        }
+
+        @Override
+        public String toString() {
+            return "LongContainer{" +
+                "metricsKeyWrapper=" + metricsKeyWrapper +
+                '}';
+        }
+    }
+
+    public static class AtomicLongContainer extends LongContainer<AtomicLong> {
+
+        public AtomicLongContainer(MetricsKeyWrapper metricsKeyWrapper) {
+            super(metricsKeyWrapper, AtomicLong::new, (responseTime, 
longAccumulator) -> longAccumulator.set(responseTime));
+        }
+
+        public AtomicLongContainer(MetricsKeyWrapper metricsKeyWrapper, 
BiConsumer<Long, AtomicLong> consumerFunc) {
+            super(metricsKeyWrapper, AtomicLong::new, consumerFunc);
+        }
+
+    }
+
+    public static class LongAccumulatorContainer extends 
LongContainer<LongAccumulator> {
+        public LongAccumulatorContainer(MetricsKeyWrapper metricsKeyWrapper, 
LongAccumulator accumulator) {
+            super(metricsKeyWrapper, () -> accumulator, (responseTime, 
longAccumulator) -> longAccumulator.accumulate(responseTime));
+        }
+    }
+
+
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetadataEvent.java
 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetadataEvent.java
new file mode 100644
index 0000000000..8d68e5a189
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetadataEvent.java
@@ -0,0 +1,109 @@
+/*
+ * 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.metadata.event;
+
+import org.apache.dubbo.metrics.event.MetricsEvent;
+import org.apache.dubbo.metrics.event.TimeCounter;
+import org.apache.dubbo.metrics.metadata.collector.MetadataMetricsCollector;
+import org.apache.dubbo.metrics.model.MetricsKey;
+import org.apache.dubbo.metrics.model.TimePair;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+
+/**
+ * Registry related events
+ */
+public class MetadataEvent extends MetricsEvent implements TimeCounter {
+    private final TimePair timePair;
+    private final MetadataMetricsCollector collector;
+    private final boolean available;
+
+    public MetadataEvent(ApplicationModel applicationModel, TimePair timePair) 
{
+        super(applicationModel);
+        this.timePair = timePair;
+        this.collector = 
applicationModel.getBeanFactory().getBean(MetadataMetricsCollector.class);
+        this.available = this.collector != null && 
collector.isCollectEnabled();
+    }
+
+    public ApplicationModel getSource() {
+        return (ApplicationModel) source;
+    }
+
+    public MetadataMetricsCollector getCollector() {
+        return collector;
+    }
+
+    public boolean isAvailable() {
+        return available;
+    }
+
+    @Override
+    public TimePair getTimePair() {
+        return timePair;
+    }
+
+    public enum Type {
+        P_TOTAL(MetricsKey.METADATA_PUSH_METRIC_NUM),
+        P_SUCCEED(MetricsKey.METADATA_PUSH_METRIC_NUM_SUCCEED),
+        P_FAILED(MetricsKey.METADATA_PUSH_METRIC_NUM_FAILED),
+
+        S_TOTAL(MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM),
+        S_SUCCEED(MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED),
+        S_FAILED(MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM_FAILED),
+
+        ;
+
+
+        private final MetricsKey metricsKey;
+        private final boolean isIncrement;
+
+
+        Type(MetricsKey metricsKey) {
+            this(metricsKey, true);
+        }
+
+        Type(MetricsKey metricsKey, boolean isIncrement) {
+            this.metricsKey = metricsKey;
+            this.isIncrement = isIncrement;
+        }
+
+        public MetricsKey getMetricsKey() {
+            return metricsKey;
+        }
+
+        public boolean isIncrement() {
+            return isIncrement;
+        }
+    }
+
+    public static class PushEvent extends MetadataEvent {
+
+        public PushEvent(ApplicationModel applicationModel, TimePair timePair) 
{
+            super(applicationModel, timePair);
+        }
+
+    }
+
+    public static class SubscribeEvent extends MetadataEvent {
+
+        public SubscribeEvent(ApplicationModel applicationModel, TimePair 
timePair) {
+            super(applicationModel, timePair);
+        }
+
+    }
+
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsListener.java
 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetadataMetricsEventMulticaster.java
similarity index 67%
copy from 
dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsListener.java
copy to 
dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetadataMetricsEventMulticaster.java
index 058f583e94..92b3c96da3 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsListener.java
+++ 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetadataMetricsEventMulticaster.java
@@ -15,24 +15,17 @@
  * limitations under the License.
  */
 
-package org.apache.dubbo.metrics.listener;
+package org.apache.dubbo.metrics.metadata.event;
 
-import org.apache.dubbo.metrics.event.MetricsEvent;
+import org.apache.dubbo.metrics.event.SimpleMetricsEventMulticaster;
 
-/**
- * Metrics Listener.
- */
-public interface MetricsListener<E extends MetricsEvent> {
+public final class MetadataMetricsEventMulticaster extends 
SimpleMetricsEventMulticaster {
 
-    default boolean isSupport(MetricsEvent event) {
-        return true;
-    }
+    public MetadataMetricsEventMulticaster() {
+        super.addListener(new MetricsPushListener());
+        super.addListener(new MetricsSubscribeListener());
 
-    /**
-     * notify event.
-     *
-     * @param event BaseMetricsEvent
-     */
-    void onEvent(E event);
+        setAvailable();
+    }
 
 }
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
new file mode 100644
index 0000000000..d08ec366c8
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetricsPushListener.java
@@ -0,0 +1,49 @@
+/*
+ * 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.metadata.event;
+
+import org.apache.dubbo.metrics.event.MetricsEvent;
+import org.apache.dubbo.metrics.listener.MetricsLifeListener;
+
+import static 
org.apache.dubbo.metrics.metadata.collector.stat.MetadataStatComposite.OP_TYPE_PUSH;
+
+public class MetricsPushListener implements 
MetricsLifeListener<MetadataEvent.PushEvent> {
+
+
+    @Override
+    public boolean isSupport(MetricsEvent event) {
+        return event instanceof MetadataEvent.PushEvent && ((MetadataEvent) 
event).isAvailable();
+    }
+
+    @Override
+    public void onEvent(MetadataEvent.PushEvent event) {
+        event.getCollector().increment(event.getSource().getApplicationName(), 
MetadataEvent.Type.P_TOTAL);
+    }
+
+    @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());
+    }
+
+    @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());
+    }
+}
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
new file mode 100644
index 0000000000..a247f539a5
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/java/org/apache/dubbo/metrics/metadata/event/MetricsSubscribeListener.java
@@ -0,0 +1,49 @@
+/*
+ * 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.metadata.event;
+
+import org.apache.dubbo.metrics.event.MetricsEvent;
+import org.apache.dubbo.metrics.listener.MetricsLifeListener;
+
+import static 
org.apache.dubbo.metrics.metadata.collector.stat.MetadataStatComposite.OP_TYPE_SUBSCRIBE;
+
+public class MetricsSubscribeListener implements 
MetricsLifeListener<MetadataEvent.SubscribeEvent> {
+
+    @Override
+    public boolean isSupport(MetricsEvent event) {
+        return event instanceof MetadataEvent.SubscribeEvent && 
((MetadataEvent) event).isAvailable();
+    }
+
+    @Override
+    public void onEvent(MetadataEvent.SubscribeEvent event) {
+        event.getCollector().increment(event.getSource().getApplicationName(), 
MetadataEvent.Type.S_TOTAL);
+    }
+
+    @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());
+    }
+
+    @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());
+    }
+
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-metadata/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector
 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector
new file mode 100644
index 0000000000..c90627a2d0
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-metadata/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector
@@ -0,0 +1 @@
+metadata-collector=org.apache.dubbo.metrics.metadata.collector.MetadataMetricsCollector
diff --git 
a/dubbo-metrics/dubbo-metrics-metadata/src/test/java/metrics/metrics/collector/MetadataMetricsCollectorTest.java
 
b/dubbo-metrics/dubbo-metrics-metadata/src/test/java/metrics/metrics/collector/MetadataMetricsCollectorTest.java
new file mode 100644
index 0000000000..a07712bccd
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-metadata/src/test/java/metrics/metrics/collector/MetadataMetricsCollectorTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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 metrics.metrics.collector;
+
+import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster;
+import org.apache.dubbo.metrics.metadata.collector.MetadataMetricsCollector;
+import org.apache.dubbo.metrics.metadata.event.MetadataEvent;
+import org.apache.dubbo.metrics.model.MetricsKey;
+import org.apache.dubbo.metrics.model.MetricsKeyWrapper;
+import org.apache.dubbo.metrics.model.TimePair;
+import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
+import org.apache.dubbo.metrics.model.sample.MetricSample;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static 
org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;
+import static 
org.apache.dubbo.metrics.metadata.collector.stat.MetadataStatComposite.OP_TYPE_PUSH;
+import static 
org.apache.dubbo.metrics.metadata.collector.stat.MetadataStatComposite.OP_TYPE_SUBSCRIBE;
+
+
+class MetadataMetricsCollectorTest {
+
+    private ApplicationModel applicationModel;
+
+    @BeforeEach
+    public void setup() {
+        FrameworkModel frameworkModel = FrameworkModel.defaultModel();
+        applicationModel = frameworkModel.newApplication();
+        ApplicationConfig config = new ApplicationConfig();
+        config.setName("MockMetrics");
+
+        applicationModel.getApplicationConfigManager().setApplication(config);
+
+    }
+
+    @AfterEach
+    public void teardown() {
+        applicationModel.destroy();
+    }
+
+    @Test
+    void testPushMetrics() throws InterruptedException {
+
+        TimePair timePair = TimePair.start();
+        GlobalMetricsEventMulticaster eventMulticaster = 
applicationModel.getBeanFactory().getOrRegisterBean(GlobalMetricsEventMulticaster.class);
+        MetadataMetricsCollector collector = 
applicationModel.getBeanFactory().getOrRegisterBean(MetadataMetricsCollector.class);
+        collector.setCollectEnabled(true);
+
+        eventMulticaster.publishEvent(new 
MetadataEvent.PushEvent(applicationModel, timePair));
+        List<MetricSample> metricSamples = collector.collect();
+
+        // push success +1
+        Assertions.assertEquals(metricSamples.size(), 1);
+        Assertions.assertTrue(metricSamples.get(0) instanceof 
GaugeMetricSample);
+        Assertions.assertEquals(metricSamples.get(0).getName(), 
MetricsKey.METADATA_PUSH_METRIC_NUM.getName());
+
+        eventMulticaster.publishFinishEvent(new 
MetadataEvent.PushEvent(applicationModel, timePair));
+        // push finish rt +1
+        metricSamples = collector.collect();
+        //num(total+success) + rt(5) = 7
+        Assertions.assertEquals(metricSamples.size(), 7);
+        long c1 = timePair.calc();
+        TimePair lastTimePair = TimePair.start();
+        eventMulticaster.publishEvent(new 
MetadataEvent.PushEvent(applicationModel, lastTimePair));
+        Thread.sleep(50);
+        // push error rt +1
+        eventMulticaster.publishErrorEvent(new 
MetadataEvent.PushEvent(applicationModel, lastTimePair));
+        long c2 = lastTimePair.calc();
+        metricSamples = collector.collect();
+
+        // num(total+success+error) + rt(5)
+        Assertions.assertEquals(metricSamples.size(), 8);
+
+        // calc rt
+        for (MetricSample sample : metricSamples) {
+            Map<String, String> tags = sample.getTags();
+            Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), 
applicationModel.getApplicationName());
+        }
+        Map<String, Long> sampleMap = 
metricSamples.stream().collect(Collectors.toMap(MetricSample::getName, k -> {
+            Number number = ((GaugeMetricSample) k).getSupplier().get();
+            return number.longValue();
+        }));
+
+        Assertions.assertEquals(sampleMap.get(new 
MetricsKeyWrapper(OP_TYPE_PUSH, 
MetricsKey.GENERIC_METRIC_RT_LAST).targetKey()), lastTimePair.calc());
+        Assertions.assertEquals(sampleMap.get(new 
MetricsKeyWrapper(OP_TYPE_PUSH, MetricsKey.GENERIC_METRIC_RT_MIN).targetKey()), 
Math.min(c1, c2));
+        Assertions.assertEquals(sampleMap.get(new 
MetricsKeyWrapper(OP_TYPE_PUSH, MetricsKey.GENERIC_METRIC_RT_MAX).targetKey()), 
Math.max(c1, c2));
+        Assertions.assertEquals(sampleMap.get(new 
MetricsKeyWrapper(OP_TYPE_PUSH, MetricsKey.GENERIC_METRIC_RT_AVG).targetKey()), 
(c1 + c2) / 2);
+        Assertions.assertEquals(sampleMap.get(new 
MetricsKeyWrapper(OP_TYPE_PUSH, MetricsKey.GENERIC_METRIC_RT_SUM).targetKey()), 
c1 + c2);
+    }
+
+    @Test
+    void testSubscribeMetrics() throws InterruptedException {
+
+        TimePair timePair = TimePair.start();
+        GlobalMetricsEventMulticaster eventMulticaster = 
applicationModel.getBeanFactory().getOrRegisterBean(GlobalMetricsEventMulticaster.class);
+        MetadataMetricsCollector collector = 
applicationModel.getBeanFactory().getOrRegisterBean(MetadataMetricsCollector.class);
+        collector.setCollectEnabled(true);
+
+        eventMulticaster.publishEvent(new 
MetadataEvent.SubscribeEvent(applicationModel, timePair));
+        List<MetricSample> metricSamples = collector.collect();
+
+        // push success +1
+        Assertions.assertEquals(metricSamples.size(), 1);
+        Assertions.assertTrue(metricSamples.get(0) instanceof 
GaugeMetricSample);
+        Assertions.assertEquals(metricSamples.get(0).getName(), 
MetricsKey.METADATA_SUBSCRIBE_METRIC_NUM.getName());
+
+        eventMulticaster.publishFinishEvent(new 
MetadataEvent.SubscribeEvent(applicationModel, timePair));
+        // push finish rt +1
+        metricSamples = collector.collect();
+        //num(total+success) + rt(5) = 7
+        Assertions.assertEquals(metricSamples.size(), 7);
+        long c1 = timePair.calc();
+        TimePair lastTimePair = TimePair.start();
+        eventMulticaster.publishEvent(new 
MetadataEvent.SubscribeEvent(applicationModel, lastTimePair));
+        Thread.sleep(50);
+        // push error rt +1
+        eventMulticaster.publishErrorEvent(new 
MetadataEvent.SubscribeEvent(applicationModel, lastTimePair));
+        long c2 = lastTimePair.calc();
+        metricSamples = collector.collect();
+
+        // num(total+success+error) + rt(5)
+        Assertions.assertEquals(metricSamples.size(), 8);
+
+        // calc rt
+        for (MetricSample sample : metricSamples) {
+            Map<String, String> tags = sample.getTags();
+            Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), 
applicationModel.getApplicationName());
+        }
+        Map<String, Long> sampleMap = 
metricSamples.stream().collect(Collectors.toMap(MetricSample::getName, k -> {
+            Number number = ((GaugeMetricSample) k).getSupplier().get();
+            return number.longValue();
+        }));
+
+        Assertions.assertEquals(sampleMap.get(new 
MetricsKeyWrapper(OP_TYPE_SUBSCRIBE, 
MetricsKey.GENERIC_METRIC_RT_LAST).targetKey()), lastTimePair.calc());
+        Assertions.assertEquals(sampleMap.get(new 
MetricsKeyWrapper(OP_TYPE_SUBSCRIBE, 
MetricsKey.GENERIC_METRIC_RT_MIN).targetKey()), Math.min(c1, c2));
+        Assertions.assertEquals(sampleMap.get(new 
MetricsKeyWrapper(OP_TYPE_SUBSCRIBE, 
MetricsKey.GENERIC_METRIC_RT_MAX).targetKey()), Math.max(c1, c2));
+        Assertions.assertEquals(sampleMap.get(new 
MetricsKeyWrapper(OP_TYPE_SUBSCRIBE, 
MetricsKey.GENERIC_METRIC_RT_AVG).targetKey()), (c1 + c2) / 2);
+        Assertions.assertEquals(sampleMap.get(new 
MetricsKeyWrapper(OP_TYPE_SUBSCRIBE, 
MetricsKey.GENERIC_METRIC_RT_SUM).targetKey()), c1 + c2);
+    }
+
+
+}
diff --git a/dubbo-metrics/pom.xml b/dubbo-metrics/pom.xml
index c504428498..835c2b1b44 100644
--- a/dubbo-metrics/pom.xml
+++ b/dubbo-metrics/pom.xml
@@ -20,6 +20,7 @@
     <modules>
         <module>dubbo-metrics-api</module>
         <module>dubbo-metrics-default</module>
+        <module>dubbo-metrics-metadata</module>
         <module>dubbo-metrics-prometheus</module>
     </modules>
     <parent>
diff --git 
a/dubbo-native-plugin/src/main/resources/META-INF/native-image/reflect-config.json
 
b/dubbo-native-plugin/src/main/resources/META-INF/native-image/reflect-config.json
index 8ffe07af6c..816a1aff40 100644
--- 
a/dubbo-native-plugin/src/main/resources/META-INF/native-image/reflect-config.json
+++ 
b/dubbo-native-plugin/src/main/resources/META-INF/native-image/reflect-config.json
@@ -2110,6 +2110,16 @@
       }
     ]
   },
+  {
+    "name": "org.apache.dubbo.metrics.MetricsScopeModelInitializer",
+    "allPublicMethods": true,
+    "methods": [
+      {
+        "name": "<init>",
+        "parameterTypes": []
+      }
+    ]
+  },
   {
     "name": "org.apache.dubbo.rpc.cluster.ConfiguratorFactory",
     "allPublicMethods": true
@@ -2908,7 +2918,7 @@
     "methods": [
       {
         "name": "<init>",
-        "parameterTypes": ["org.apache.dubbo.rpc.model.FrameworkModel"]
+        "parameterTypes": ["org.apache.dubbo.rpc.model.ApplicationModel"]
       }
     ]
   }
diff --git a/dubbo-registry/dubbo-registry-api/pom.xml 
b/dubbo-registry/dubbo-registry-api/pom.xml
index 8cb1496544..f9c580f8c9 100644
--- a/dubbo-registry/dubbo-registry-api/pom.xml
+++ b/dubbo-registry/dubbo-registry-api/pom.xml
@@ -80,5 +80,23 @@
             <artifactId>zookeeper</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-metrics-api</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-metrics-default</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-metrics-metadata</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscovery.java
 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscovery.java
index 6241fe1778..edb974da48 100644
--- 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscovery.java
+++ 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscovery.java
@@ -16,14 +16,6 @@
  */
 package org.apache.dubbo.registry.client;
 
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
 import org.apache.dubbo.common.logger.LoggerFactory;
@@ -34,6 +26,9 @@ import org.apache.dubbo.metadata.MetadataInfo;
 import org.apache.dubbo.metadata.report.MetadataReport;
 import org.apache.dubbo.metadata.report.MetadataReportInstance;
 import 
org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;
+import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster;
+import org.apache.dubbo.metrics.metadata.event.MetadataEvent;
+import org.apache.dubbo.metrics.model.TimePair;
 import org.apache.dubbo.registry.NotifyListener;
 import 
org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener;
 import org.apache.dubbo.registry.client.metadata.MetadataUtils;
@@ -41,6 +36,14 @@ import 
org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils;
 import org.apache.dubbo.registry.client.metadata.store.MetaCacheManager;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
 import static 
org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_INFO_CACHE_EXPIRE;
 import static 
org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_INFO_CACHE_SIZE;
 import static 
org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE;
@@ -225,12 +228,19 @@ public abstract class AbstractServiceDiscovery implements 
ServiceDiscovery {
             // try to load metadata from remote.
             int triedTimes = 0;
             while (triedTimes < 3) {
+
+                TimePair timePair = TimePair.start();
+                GlobalMetricsEventMulticaster eventMulticaster = 
applicationModel.getBeanFactory().getBean(GlobalMetricsEventMulticaster.class);
+                eventMulticaster.publishEvent(new 
MetadataEvent.SubscribeEvent(applicationModel, timePair));
+
                 metadata = MetadataUtils.getRemoteMetadata(revision, 
instances, metadataReport);
 
                 if (metadata != MetadataInfo.EMPTY) {// succeeded
                     metadata.init();
+                    eventMulticaster.publishFinishEvent(new 
MetadataEvent.SubscribeEvent(applicationModel, timePair));
                     break;
                 } else {// failed
+                    eventMulticaster.publishErrorEvent(new 
MetadataEvent.SubscribeEvent(applicationModel, timePair));
                     if (triedTimes > 0) {
                         if (logger.isDebugEnabled()) {
                             logger.debug("Retry the " + triedTimes + " times 
to get metadata for revision=" + revision);
@@ -301,7 +311,7 @@ public abstract class AbstractServiceDiscovery implements 
ServiceDiscovery {
      * Can be override if registry support update instance directly.
      * <br/>
      * NOTICE: Remind to update {@link 
AbstractServiceDiscovery#serviceInstance}'s reference if updated
-     *         and report metadata by {@link 
AbstractServiceDiscovery#reportMetadata(MetadataInfo)}
+     * and report metadata by {@link 
AbstractServiceDiscovery#reportMetadata(MetadataInfo)}
      *
      * @param oldServiceInstance origin service instance
      * @param newServiceInstance new service instance
@@ -351,12 +361,21 @@ public abstract class AbstractServiceDiscovery implements 
ServiceDiscovery {
         if (metadataInfo == null) {
             return;
         }
+        TimePair timePair = TimePair.start();
+        GlobalMetricsEventMulticaster eventMulticaster = 
applicationModel.getBeanFactory().getBean(GlobalMetricsEventMulticaster.class);
+        eventMulticaster.publishEvent(new 
MetadataEvent.PushEvent(applicationModel, timePair));
         if (metadataReport != null) {
             SubscriberMetadataIdentifier identifier = new 
SubscriberMetadataIdentifier(serviceName, metadataInfo.getRevision());
             if ((DEFAULT_METADATA_STORAGE_TYPE.equals(metadataType) && 
metadataReport.shouldReportMetadata()) || 
REMOTE_METADATA_STORAGE_TYPE.equals(metadataType)) {
-                metadataReport.publishAppMetadata(identifier, metadataInfo);
+                try {
+                    metadataReport.publishAppMetadata(identifier, 
metadataInfo);
+                } catch (IllegalStateException e) {
+                    eventMulticaster.publishErrorEvent(new 
MetadataEvent.PushEvent(applicationModel, timePair));
+                    throw e;
+                }
             }
         }
+        eventMulticaster.publishFinishEvent(new 
MetadataEvent.PushEvent(applicationModel, timePair));
         MetadataInfo clonedMetadataInfo = metadataInfo.clone();
         metadataInfos.put(metadataInfo.getRevision(), new 
MetadataInfoStat(clonedMetadataInfo));
     }
diff --git a/dubbo-test/dubbo-dependencies-all/pom.xml 
b/dubbo-test/dubbo-dependencies-all/pom.xml
index f97e0a6945..66f84b58f6 100644
--- a/dubbo-test/dubbo-dependencies-all/pom.xml
+++ b/dubbo-test/dubbo-dependencies-all/pom.xml
@@ -148,6 +148,10 @@
             <groupId>org.apache.dubbo</groupId>
             <artifactId>dubbo-metrics-default</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-metrics-metadata</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.dubbo</groupId>
             <artifactId>dubbo-metrics-prometheus</artifactId>

Reply via email to