add metadata rt metrics (#2363)

diff --git a/config/metric_config.go b/config/metric_config.go
index 4ffa0b1..a6b8749 100644
--- a/config/metric_config.go
+++ b/config/metric_config.go
@@ -56,6 +56,7 @@
 	defaultMetricsReportConfig.Path = mc.Path
 	defaultMetricsReportConfig.PushGatewayAddress = mc.PushGatewayAddress
 	defaultMetricsReportConfig.SummaryMaxAge = mc.SummaryMaxAge
+	defaultMetricsReportConfig.Protocol = mc.Protocol
 	return defaultMetricsReportConfig
 }
 
diff --git a/metadata/report/reporter_metric.go b/metadata/report/reporter_metric.go
index a8369fe..5ca0995 100644
--- a/metadata/report/reporter_metric.go
+++ b/metadata/report/reporter_metric.go
@@ -42,7 +42,6 @@
 	err := r.MetadataReport.StoreProviderMetadata(i, s)
 	event.Succ = err == nil
 	event.End = time.Now()
-	event.Attachment = make(map[string]string)
 	event.Attachment[constant.InterfaceKey] = i.ServiceInterface
 	metrics.Publish(event)
 	return err
diff --git a/metrics/api.go b/metrics/api.go
index 7bc530b..fdc69c1 100644
--- a/metrics/api.go
+++ b/metrics/api.go
@@ -17,6 +17,14 @@
 
 package metrics
 
+import (
+	"sync"
+)
+
+import (
+	"dubbo.apache.org/dubbo-go/v3/metrics/util/aggregate"
+)
+
 var registries = make(map[string]func(*ReporterConfig) MetricRegistry)
 var collectors = make([]CollectorFunc, 0)
 var registry MetricRegistry
@@ -24,19 +32,19 @@
 // CollectorFunc used to extend more indicators
 type CollectorFunc func(MetricRegistry, *ReporterConfig)
 
-const defaultRegistry = "prometheus"
-
 // Init Metrics module
 func Init(config *ReporterConfig) {
-	regFunc, ok := registries[config.Protocol]
-	if !ok {
-		regFunc = registries[defaultRegistry] // default
+	if config.Enable {
+		// defalut protocol is already set in metricConfig
+		regFunc, ok := registries[config.Protocol]
+		if ok {
+			registry = regFunc(config)
+			for _, co := range collectors {
+				co(registry, config)
+			}
+			registry.Export()
+		}
 	}
-	registry = regFunc(config)
-	for _, co := range collectors {
-		co(registry, config)
-	}
-	registry.Export()
 }
 
 // SetRegistry extend more MetricRegistry, default PrometheusRegistry
@@ -44,7 +52,7 @@
 	registries[name] = v
 }
 
-// AddCollector add more indicators, like  metadata、sla、configcenter、metadata etc
+// AddCollector add more indicators, like  metadata、sla、configcenter etc
 func AddCollector(name string, fun func(MetricRegistry, *ReporterConfig)) {
 	collectors = append(collectors, fun)
 }
@@ -142,15 +150,13 @@
 	Inc(succ bool)
 }
 
-func NewStatesMetrics(total func() *MetricId, succ func() *MetricId, fail func() *MetricId, reg MetricRegistry) StatesMetrics {
+func NewStatesMetrics(total *MetricId, succ *MetricId, fail *MetricId, reg MetricRegistry) StatesMetrics {
 	return &DefaultStatesMetric{total: total, succ: succ, fail: fail, r: reg}
 }
 
 type DefaultStatesMetric struct {
-	r     MetricRegistry
-	total func() *MetricId
-	succ  func() *MetricId
-	fail  func() *MetricId
+	r                 MetricRegistry
+	total, succ, fail *MetricId
 }
 
 func (c DefaultStatesMetric) Inc(succ bool) {
@@ -161,32 +167,73 @@
 	}
 }
 func (c DefaultStatesMetric) Success() {
-	c.r.Counter(c.total()).Inc()
-	c.r.Counter(c.succ()).Inc()
+	c.r.Counter(c.total).Inc()
+	c.r.Counter(c.succ).Inc()
 }
 
 func (c DefaultStatesMetric) AddSuccess(v float64) {
-	c.r.Counter(c.total()).Add(v)
-	c.r.Counter(c.succ()).Add(v)
+	c.r.Counter(c.total).Add(v)
+	c.r.Counter(c.succ).Add(v)
 }
 
 func (c DefaultStatesMetric) Fail() {
-	c.r.Counter(c.total()).Inc()
-	c.r.Counter(c.fail()).Inc()
+	c.r.Counter(c.total).Inc()
+	c.r.Counter(c.fail).Inc()
 }
 
 func (c DefaultStatesMetric) AddFailed(v float64) {
-	c.r.Counter(c.total()).Add(v)
-	c.r.Counter(c.fail()).Add(v)
+	c.r.Counter(c.total).Add(v)
+	c.r.Counter(c.fail).Add(v)
 }
 
-// TimeMetrics muliti metrics, include min(Gauge)、max(Gauge)、avg(Gauge)、sum(Gauge)、last(Gauge),call MetricRegistry to expose
+// TimeMetric muliti metrics, include min(Gauge)、max(Gauge)、avg(Gauge)、sum(Gauge)、last(Gauge),call MetricRegistry to expose
 // see dubbo-java org.apache.dubbo.metrics.aggregate.TimeWindowAggregator
-type TimeMetrics interface {
+type TimeMetric interface {
 	Record(float64)
 }
 
-// NewTimeMetrics init and write all data to registry
-func NewTimeMetrics(name string, l MetricLevel) {
+const (
+	defaultBucketNum         = 10
+	defalutTimeWindowSeconds = 120
+)
 
+// NewTimeMetric init and write all data to registry
+func NewTimeMetric(min, max, avg, sum, last *MetricId, mr MetricRegistry) TimeMetric {
+	return &DefaultTimeMetric{r: mr, min: min, max: max, avg: avg, sum: sum, last: last,
+		agg: aggregate.NewTimeWindowAggregator(defaultBucketNum, defalutTimeWindowSeconds)}
+}
+
+type DefaultTimeMetric struct {
+	r                        MetricRegistry
+	agg                      *aggregate.TimeWindowAggregator
+	min, max, avg, sum, last *MetricId
+}
+
+func (m *DefaultTimeMetric) Record(v float64) {
+	m.agg.Add(v)
+	result := m.agg.Result()
+	m.r.Gauge(m.max).Set(result.Max)
+	m.r.Gauge(m.min).Set(result.Min)
+	m.r.Gauge(m.avg).Set(result.Avg)
+	m.r.Gauge(m.sum).Set(result.Total)
+	m.r.Gauge(m.last).Set(v)
+}
+
+// cache if needed,  TimeMetrics must cached
+var metricsCache map[string]interface{} = make(map[string]interface{})
+var metricsCacheMutex sync.RWMutex
+
+func ComputeIfAbsentCache(key string, supplier func() interface{}) interface{} {
+	metricsCacheMutex.RLock()
+	v, ok := metricsCache[key]
+	metricsCacheMutex.RUnlock()
+	if ok {
+		return v
+	} else {
+		metricsCacheMutex.Lock()
+		defer metricsCacheMutex.Unlock()
+		n := supplier()
+		metricsCache[key] = n
+		return n
+	}
 }
diff --git a/metrics/metadata/collector.go b/metrics/metadata/collector.go
index 62653a1..16740d3 100644
--- a/metrics/metadata/collector.go
+++ b/metrics/metadata/collector.go
@@ -53,6 +53,8 @@
 					c.handleMetadataPush(event)
 				case MetadataSub:
 					c.handleMetadataSub(event)
+				case SubscribeServiceRt:
+					c.handleSubscribeService(event)
 				default:
 				}
 			}
@@ -61,31 +63,59 @@
 }
 
 func (c *MetadataMetricCollector) handleMetadataPush(event *MetadataMetricEvent) {
-	m := newStatesMetricFunc(metadataPushNum, metadataPushNumSucceed, metadataPushNumFailed, metrics.GetApplicationLevel(), c.r)
+	m := metrics.ComputeIfAbsentCache(dubboMetadataPush, func() interface{} {
+		return newStatesMetricFunc(metadataPushNum, metadataPushNumSucceed, metadataPushNumFailed, metrics.GetApplicationLevel(), c.r)
+	}).(metrics.StatesMetrics)
 	m.Inc(event.Succ)
-	// TODO add RT metric dubbo_push_rt_milliseconds
+	metric := metrics.ComputeIfAbsentCache(dubboPushRt, func() interface{} {
+		return newTimeMetrics(pushRtMin, pushRtMax, pushRtAvg, pushRtSum, pushRtLast, metrics.GetApplicationLevel(), c.r)
+	}).(metrics.TimeMetric)
+	metric.Record(event.CostMs())
 }
 
 func (c *MetadataMetricCollector) handleMetadataSub(event *MetadataMetricEvent) {
-	m := newStatesMetricFunc(metadataSubNum, metadataSubNumSucceed, metadataSubNumFailed, metrics.GetApplicationLevel(), c.r)
+	m := metrics.ComputeIfAbsentCache(dubboMetadataSubscribe, func() interface{} {
+		return newStatesMetricFunc(metadataSubNum, metadataSubNumSucceed, metadataSubNumFailed, metrics.GetApplicationLevel(), c.r)
+	}).(metrics.StatesMetrics)
 	m.Inc(event.Succ)
-	// TODO add RT metric dubbo_subscribe_rt_milliseconds
+	metric := metrics.ComputeIfAbsentCache(dubboSubscribeRt, func() interface{} {
+		return newTimeMetrics(subscribeRtMin, subscribeRtMax, subscribeRtAvg, subscribeRtSum, subscribeRtLast, metrics.GetApplicationLevel(), c.r)
+	}).(metrics.TimeMetric)
+	metric.Record(event.CostMs())
 }
 
 func (c *MetadataMetricCollector) handleStoreProvider(event *MetadataMetricEvent) {
-	level := metrics.NewServiceMetric(event.Attachment[constant.InterfaceKey])
-	m := newStatesMetricFunc(metadataStoreProvider, metadataStoreProviderSucceed, metadataStoreProviderFailed, level, c.r)
+	interfaceName := event.Attachment[constant.InterfaceKey]
+	m := metrics.ComputeIfAbsentCache(dubboMetadataStoreProvider+":"+interfaceName, func() interface{} {
+		return newStatesMetricFunc(metadataStoreProvider, metadataStoreProviderSucceed, metadataStoreProviderFailed,
+			metrics.NewServiceMetric(interfaceName), c.r)
+	}).(metrics.StatesMetrics)
 	m.Inc(event.Succ)
-	// TODO add RT metric dubbo_store_provider_interface_rt_milliseconds
+	metric := metrics.ComputeIfAbsentCache(dubboStoreProviderInterfaceRt+":"+interfaceName, func() interface{} {
+		return newTimeMetrics(storeProviderInterfaceRtMin, storeProviderInterfaceRtMax, storeProviderInterfaceRtAvg,
+			storeProviderInterfaceRtSum, storeProviderInterfaceRtLast, metrics.NewServiceMetric(interfaceName), c.r)
+	}).(metrics.TimeMetric)
+	metric.Record(event.CostMs())
 }
 
-func newStatesMetricFunc(total *metrics.MetricKey, succ *metrics.MetricKey, fail *metrics.MetricKey, level metrics.MetricLevel, reg metrics.MetricRegistry) metrics.StatesMetrics {
-	return metrics.NewStatesMetrics(
-		func() *metrics.MetricId { return metrics.NewMetricId(total, level) },
-		func() *metrics.MetricId { return metrics.NewMetricId(succ, level) },
-		func() *metrics.MetricId { return metrics.NewMetricId(fail, level) },
-		reg,
-	)
+func (c *MetadataMetricCollector) handleSubscribeService(event *MetadataMetricEvent) {
+	interfaceName := event.Attachment[constant.InterfaceKey]
+	metric := metrics.ComputeIfAbsentCache(dubboSubscribeServiceRt+":"+interfaceName, func() interface{} {
+		return newTimeMetrics(subscribeServiceRtMin, subscribeServiceRtMax, subscribeServiceRtAvg, subscribeServiceRtSum,
+			subscribeServiceRtLast, metrics.NewServiceMetric(interfaceName), c.r)
+	}).(metrics.TimeMetric)
+	metric.Record(event.CostMs())
+}
+
+func newStatesMetricFunc(total *metrics.MetricKey, succ *metrics.MetricKey, fail *metrics.MetricKey,
+	level metrics.MetricLevel, reg metrics.MetricRegistry) metrics.StatesMetrics {
+	return metrics.NewStatesMetrics(metrics.NewMetricId(total, level), metrics.NewMetricId(succ, level),
+		metrics.NewMetricId(fail, level), reg)
+}
+
+func newTimeMetrics(min, max, avg, sum, last *metrics.MetricKey, level metrics.MetricLevel, mr metrics.MetricRegistry) metrics.TimeMetric {
+	return metrics.NewTimeMetric(metrics.NewMetricId(min, level), metrics.NewMetricId(max, level), metrics.NewMetricId(avg, level),
+		metrics.NewMetricId(sum, level), metrics.NewMetricId(last, level), mr)
 }
 
 type MetadataMetricEvent struct {
@@ -105,5 +135,5 @@
 }
 
 func NewMetadataMetricTimeEvent(n MetricName) *MetadataMetricEvent {
-	return &MetadataMetricEvent{Name: n, Start: time.Now()}
+	return &MetadataMetricEvent{Name: n, Start: time.Now(), Attachment: make(map[string]string)}
 }
diff --git a/metrics/metadata/metric_set.go b/metrics/metadata/metric_set.go
index 1eaad0e..e7ade6e 100644
--- a/metrics/metadata/metric_set.go
+++ b/metrics/metadata/metric_set.go
@@ -33,55 +33,76 @@
 	SubscribeServiceRt
 )
 
+const (
+	dubboMetadataPush             = "dubbo_metadata_push_num"
+	dubboPushRt                   = "dubbo_push_rt_milliseconds"
+	dubboMetadataSubscribe        = "dubbo_metadata_subscribe_num"
+	dubboSubscribeRt              = "dubbo_subscribe_rt_milliseconds"
+	dubboMetadataStoreProvider    = "dubbo_metadata_store_provider"
+	dubboStoreProviderInterfaceRt = "dubbo_store_provider_interface_rt_milliseconds"
+	dubboSubscribeServiceRt       = "dubbo_subscribe_service_rt_milliseconds"
+)
+
+const (
+	totalSuffix  = "_total"
+	succSuffix   = "_succeed_total"
+	failedSuffix = "_failed_total"
+	sumSuffix    = "_sum"
+	lastSuffix   = "_last"
+	minSuffix    = "_min"
+	maxSuffix    = "_max"
+	avgSuffix    = "_avg"
+)
+
 var (
 	// app level
-	metadataPushNum        = metrics.NewMetricKey("dubbo_metadata_push_num_total", "Total Num")
-	metadataPushNumSucceed = metrics.NewMetricKey("dubbo_metadata_push_num_succeed_total", "Succeed Push Num")
-	metadataPushNumFailed  = metrics.NewMetricKey("dubbo_metadata_push_num_failed_total", "Failed Push Num")
+	metadataPushNum        = metrics.NewMetricKey(dubboMetadataPush+totalSuffix, "Total Num")
+	metadataPushNumSucceed = metrics.NewMetricKey(dubboMetadataPush+succSuffix, "Succeed Push Num")
+	metadataPushNumFailed  = metrics.NewMetricKey(dubboMetadataPush+failedSuffix, "Failed Push Num")
 	// app level
-	metadataSubNum        = metrics.NewMetricKey("dubbo_metadata_subscribe_num_total", "Total Metadata Subscribe Num")
-	metadataSubNumSucceed = metrics.NewMetricKey("dubbo_metadata_subscribe_num_succeed_total", "Succeed Metadata Subscribe Num")
-	metadataSubNumFailed  = metrics.NewMetricKey("dubbo_metadata_subscribe_num_failed_total", "Failed Metadata Subscribe Num")
+	metadataSubNum        = metrics.NewMetricKey(dubboMetadataSubscribe+totalSuffix, "Total Metadata Subscribe Num")
+	metadataSubNumSucceed = metrics.NewMetricKey(dubboMetadataSubscribe+succSuffix, "Succeed Metadata Subscribe Num")
+	metadataSubNumFailed  = metrics.NewMetricKey(dubboMetadataSubscribe+failedSuffix, "Failed Metadata Subscribe Num")
 	// app level
-	pushRtSum  = metrics.NewMetricKey("dubbo_push_rt_milliseconds_sum", "Sum Response Time")
-	pushRtLast = metrics.NewMetricKey("dubbo_push_rt_milliseconds_last", "Last Response Time")
-	pushRtMin  = metrics.NewMetricKey("dubbo_push_rt_milliseconds_min", "Min Response Time")
-	pushRtMax  = metrics.NewMetricKey("dubbo_push_rt_milliseconds_max", "Max Response Time")
-	pushRtAvg  = metrics.NewMetricKey("dubbo_push_rt_milliseconds_avg", "Average Response Time")
+	pushRtSum  = metrics.NewMetricKey(dubboPushRt+sumSuffix, "Sum Response Time")
+	pushRtLast = metrics.NewMetricKey(dubboPushRt+lastSuffix, "Last Response Time")
+	pushRtMin  = metrics.NewMetricKey(dubboPushRt+minSuffix, "Min Response Time")
+	pushRtMax  = metrics.NewMetricKey(dubboPushRt+maxSuffix, "Max Response Time")
+	pushRtAvg  = metrics.NewMetricKey(dubboPushRt+avgSuffix, "Average Response Time")
 	// app level
-	subscribeRtSum  = metrics.NewMetricKey("dubbo_subscribe_rt_milliseconds_sum", "Sum Response Time")
-	subscribeRtLast = metrics.NewMetricKey("dubbo_subscribe_rt_milliseconds_last", "Last Response Time")
-	subscribeRtMin  = metrics.NewMetricKey("dubbo_subscribe_rt_milliseconds_min", "Min Response Time")
-	subscribeRtMax  = metrics.NewMetricKey("dubbo_subscribe_rt_milliseconds_max", "Max Response Time")
-	subscribeRtAvg  = metrics.NewMetricKey("dubbo_subscribe_rt_milliseconds_avg", "Average Response Time")
+	subscribeRtSum  = metrics.NewMetricKey(dubboSubscribeRt+sumSuffix, "Sum Response Time")
+	subscribeRtLast = metrics.NewMetricKey(dubboSubscribeRt+lastSuffix, "Last Response Time")
+	subscribeRtMin  = metrics.NewMetricKey(dubboSubscribeRt+minSuffix, "Min Response Time")
+	subscribeRtMax  = metrics.NewMetricKey(dubboSubscribeRt+maxSuffix, "Max Response Time")
+	subscribeRtAvg  = metrics.NewMetricKey(dubboSubscribeRt+avgSuffix, "Average Response Time")
 
 	/*
 	   # HELP dubbo_metadata_store_provider_succeed_total Succeed Store Provider Metadata
 	   # TYPE dubbo_metadata_store_provider_succeed_total gauge
-	   dubbo_metadata_store_provider_succeed_total{application_name="metrics-provider",hostname="foghostdeMacBook-Pro.local",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService2",ip="10.252.156.213",} 1.0
-	   dubbo_metadata_store_provider_succeed_total{application_name="metrics-provider",hostname="foghostdeMacBook-Pro.local",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="10.252.156.213",} 1.0
+	   dubbo_metadata_store_provider_succeed_total{application_name="metrics-provider",hostname="localhost",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService2",ip="10.252.156.213",} 1.0
+	   dubbo_metadata_store_provider_succeed_total{application_name="metrics-provider",hostname="localhost",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="10.252.156.213",} 1.0
 	*/
 	// service level
-	metadataStoreProviderFailed  = metrics.NewMetricKey("dubbo_metadata_store_provider_failed_total", "Total Failed Provider Metadata Store")
-	metadataStoreProviderSucceed = metrics.NewMetricKey("dubbo_metadata_store_provider_succeed_total", "Total Succeed Provider Metadata Store")
-	metadataStoreProvider        = metrics.NewMetricKey("dubbo_metadata_store_provider_total", "Total Provider Metadata Store")
+	metadataStoreProviderFailed  = metrics.NewMetricKey(dubboMetadataStoreProvider+failedSuffix, "Total Failed Provider Metadata Store")
+	metadataStoreProviderSucceed = metrics.NewMetricKey(dubboMetadataStoreProvider+succSuffix, "Total Succeed Provider Metadata Store")
+	metadataStoreProvider        = metrics.NewMetricKey(dubboMetadataStoreProvider+totalSuffix, "Total Provider Metadata Store")
 
 	/*
 	   # HELP dubbo_store_provider_interface_rt_milliseconds_avg Average Response Time
 	   # TYPE dubbo_store_provider_interface_rt_milliseconds_avg gauge
-	   dubbo_store_provider_interface_rt_milliseconds_avg{application_name="metrics-provider",application_version="3.2.1",git_commit_id="20de8b22ffb2a23531f6d9494a4963fcabd52561",hostname="foghostdeMacBook-Pro.local",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="10.252.156.213",} 504.0
-	   dubbo_store_provider_interface_rt_milliseconds_avg{application_name="metrics-provider",application_version="3.2.1",git_commit_id="20de8b22ffb2a23531f6d9494a4963fcabd52561",hostname="foghostdeMacBook-Pro.local",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService2",ip="10.252.156.213",} 10837.0
+	   dubbo_store_provider_interface_rt_milliseconds_avg{application_name="metrics-provider",application_version="3.2.1",git_commit_id="20de8b22ffb2a23531f6d9494a4963fcabd52561",hostname="localhost",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService",ip="10.252.156.213",} 504.0
+	   dubbo_store_provider_interface_rt_milliseconds_avg{application_name="metrics-provider",application_version="3.2.1",git_commit_id="20de8b22ffb2a23531f6d9494a4963fcabd52561",hostname="localhost",interface="org.apache.dubbo.samples.metrics.prometheus.api.DemoService2",ip="10.252.156.213",} 10837.0
 	*/
 	// service level
-	storeProviderInterfaceRtAvg  = metrics.NewMetricKey("dubbo_store_provider_interface_rt_milliseconds_avg", "Average Store Provider Interface Time")
-	storeProviderInterfaceRtLast = metrics.NewMetricKey("dubbo_store_provider_interface_rt_milliseconds_last", "Last Store Provider Interface Time")
-	storeProviderInterfaceRtMax  = metrics.NewMetricKey("dubbo_store_provider_interface_rt_milliseconds_max", "Max Store Provider Interface Time")
-	storeProviderInterfaceRtMin  = metrics.NewMetricKey("dubbo_store_provider_interface_rt_milliseconds_min", "Min Store Provider Interface Time")
-	storeProviderInterfaceRtSum  = metrics.NewMetricKey("dubbo_store_provider_interface_rt_milliseconds_sum", "Sum Store Provider Interface Time")
+	storeProviderInterfaceRtAvg  = metrics.NewMetricKey(dubboStoreProviderInterfaceRt+avgSuffix, "Average Store Provider Interface Time")
+	storeProviderInterfaceRtLast = metrics.NewMetricKey(dubboStoreProviderInterfaceRt+lastSuffix, "Last Store Provider Interface Time")
+	storeProviderInterfaceRtMax  = metrics.NewMetricKey(dubboStoreProviderInterfaceRt+maxSuffix, "Max Store Provider Interface Time")
+	storeProviderInterfaceRtMin  = metrics.NewMetricKey(dubboStoreProviderInterfaceRt+minSuffix, "Min Store Provider Interface Time")
+	storeProviderInterfaceRtSum  = metrics.NewMetricKey(dubboStoreProviderInterfaceRt+sumSuffix, "Sum Store Provider Interface Time")
 
-	subscribeServiceRtLast = metrics.NewMetricKey("dubbo_subscribe_service_rt_milliseconds_last", "Last Subscribe Service Time")
-	subscribeServiceRtMax  = metrics.NewMetricKey("dubbo_subscribe_service_rt_milliseconds_max", "Max Subscribe Service Time")
-	subscribeServiceRtMin  = metrics.NewMetricKey("dubbo_subscribe_service_rt_milliseconds_min", "Min Subscribe Service Time")
-	subscribeServiceRtSum  = metrics.NewMetricKey("dubbo_subscribe_service_rt_milliseconds_sum", "Sum Subscribe Service Time")
-	subscribeServiceRtAvg  = metrics.NewMetricKey("dubbo_subscribe_service_rt_milliseconds_avg", "Average Subscribe Service Time")
+	subscribeServiceRtLast = metrics.NewMetricKey(dubboSubscribeServiceRt+lastSuffix, "Last Subscribe Service Time")
+	subscribeServiceRtMax  = metrics.NewMetricKey(dubboSubscribeServiceRt+maxSuffix, "Max Subscribe Service Time")
+	subscribeServiceRtMin  = metrics.NewMetricKey(dubboSubscribeServiceRt+minSuffix, "Min Subscribe Service Time")
+	subscribeServiceRtSum  = metrics.NewMetricKey(dubboSubscribeServiceRt+sumSuffix, "Sum Subscribe Service Time")
+	subscribeServiceRtAvg  = metrics.NewMetricKey(dubboSubscribeServiceRt+avgSuffix, "Average Subscribe Service Time")
 )
diff --git a/registry/servicediscovery/service_discovery_registry.go b/registry/servicediscovery/service_discovery_registry.go
index 0b719ee..53b6050 100644
--- a/registry/servicediscovery/service_discovery_registry.go
+++ b/registry/servicediscovery/service_discovery_registry.go
@@ -21,6 +21,7 @@
 	"bytes"
 	"strings"
 	"sync"
+	"time"
 )
 
 import (
@@ -39,6 +40,8 @@
 	"dubbo.apache.org/dubbo-go/v3/metadata/mapping"
 	"dubbo.apache.org/dubbo-go/v3/metadata/service"
 	"dubbo.apache.org/dubbo-go/v3/metadata/service/local"
+	"dubbo.apache.org/dubbo-go/v3/metrics"
+	metricMetadata "dubbo.apache.org/dubbo-go/v3/metrics/metadata"
 	"dubbo.apache.org/dubbo-go/v3/registry"
 	_ "dubbo.apache.org/dubbo-go/v3/registry/event"
 	"dubbo.apache.org/dubbo-go/v3/registry/servicediscovery/synthesizer"
@@ -244,7 +247,12 @@
 	}
 	s.serviceListeners[serviceNamesKey] = listener
 	listener.AddListenerAndNotify(protocolServiceKey, notify)
+	event := metricMetadata.NewMetadataMetricTimeEvent(metricMetadata.SubscribeServiceRt)
 	err = s.serviceDiscovery.AddListener(listener)
+	event.Succ = err != nil
+	event.End = time.Now()
+	event.Attachment[constant.InterfaceKey] = url.Interface()
+	metrics.Publish(event)
 	if err != nil {
 		logger.Errorf("add instance listener catch error,url:%s err:%s", url.String(), err.Error())
 	}