You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2023/09/19 02:23:04 UTC

[dubbo] branch 3.2 updated: Service metrics (#13033)

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 575c3392ec Service metrics (#13033)
575c3392ec is described below

commit 575c3392ec0b30144ddb050c678798638dd2e2af
Author: songxiaosheng <so...@elastic.link>
AuthorDate: Tue Sep 19 10:22:58 2023 +0800

    Service metrics (#13033)
    
    * :zap: support service metric level
    
    * :zap: support service metric level
    
    * :zap: support service metric level
    
    * :zap: support service metric level
    
    * :white_check_mark: add ServiceMetricsTest
    
    * :white_check_mark: add ServiceMetricsTest
    
    * :white_check_mark: add ServiceMetricsTest
    
    * :zap: servicelevel config init opt
    
    * :zap: servicelevel config init opt
    
    * :zap: servicelevel config init opt
    
    * :zap: servicelevel config init opt
    
    * :zap: servicelevel config init opt
    
    ---------
    
    Co-authored-by: Albumen Kevin <jh...@gmail.com>
---
 .../filter/support/MetricsClusterFilter.java       |  5 ++-
 .../org/apache/dubbo/config/MetricsConfig.java     | 14 +++++++
 .../org/apache/dubbo/config/ServiceConfig.java     | 12 +++---
 .../src/main/resources/META-INF/dubbo.xsd          |  5 +++
 .../dubbo/metrics/data/MethodStatComposite.java    |  5 ++-
 .../apache/dubbo/metrics/data/RtStatComposite.java |  4 +-
 .../dubbo/metrics/event/MetricsInitEvent.java      |  4 +-
 .../apache/dubbo/metrics/model/MethodMetric.java   | 43 +++++++++++++++++-----
 .../collector/AggregateMetricsCollector.java       | 26 +++++++------
 .../collector/HistogramMetricsCollector.java       |  5 ++-
 .../apache/dubbo/metrics/event/RequestEvent.java   |  8 ++--
 .../apache/dubbo/metrics/filter/MetricsFilter.java |  5 ++-
 .../collector/AggregateMetricsCollectorTest.java   | 14 +++----
 .../metrics/collector/DefaultCollectorTest.java    |  6 +--
 .../metrics/collector/InitServiceMetricsTest.java  |  3 +-
 .../metrics/metrics/model/MethodMetricTest.java    | 24 +++++++++++-
 16 files changed, 134 insertions(+), 49 deletions(-)

diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsClusterFilter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsClusterFilter.java
index 5634202384..9a53935032 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsClusterFilter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsClusterFilter.java
@@ -23,6 +23,7 @@ import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
 import org.apache.dubbo.metrics.event.MetricsDispatcher;
 import org.apache.dubbo.metrics.event.MetricsEventBus;
 import org.apache.dubbo.metrics.event.RequestEvent;
+import org.apache.dubbo.metrics.model.MethodMetric;
 import org.apache.dubbo.rpc.BaseFilter;
 import org.apache.dubbo.rpc.Invocation;
 import org.apache.dubbo.rpc.Invoker;
@@ -42,6 +43,7 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener,
     private DefaultMetricsCollector collector;
     private String appName;
     private MetricsDispatcher metricsDispatcher;
+    private boolean serviceLevel;
 
     @Override
     public void setApplicationModel(ApplicationModel applicationModel) {
@@ -49,6 +51,7 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener,
         this.collector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
         this.appName = applicationModel.tryGetApplicationName();
         this.metricsDispatcher = applicationModel.getBeanFactory().getBean(MetricsDispatcher.class);
+        this.serviceLevel = MethodMetric.isServiceLevel(applicationModel);
     }
 
     @Override
@@ -73,7 +76,7 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener,
         if (t instanceof RpcException) {
             RpcException e = (RpcException) t;
             if (e.isForbidden()) {
-                MetricsEventBus.publish(RequestEvent.toRequestErrorEvent(applicationModel, appName, metricsDispatcher, invocation, CONSUMER_SIDE, e.getCode()));
+                MetricsEventBus.publish(RequestEvent.toRequestErrorEvent(applicationModel, appName, metricsDispatcher, invocation, CONSUMER_SIDE, e.getCode(), serviceLevel));
             }
         }
     }
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 129391af72..98d05209a5 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
@@ -104,6 +104,12 @@ public class MetricsConfig extends AbstractConfig {
 
     private Boolean enableRpc;
 
+    /**
+     * The level of the metrics, the value can be "SERVICE", "METHOD", default is method.
+     */
+    private String rpcLevel;
+
+
     public MetricsConfig() {
     }
 
@@ -134,6 +140,14 @@ public class MetricsConfig extends AbstractConfig {
         return enableJvm;
     }
 
+    public String getRpcLevel() {
+        return rpcLevel;
+    }
+
+    public void setRpcLevel(String rpcLevel) {
+        this.rpcLevel = rpcLevel;
+    }
+
     public void setEnableJvm(Boolean enableJvm) {
         this.enableJvm = enableJvm;
     }
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 7d14934057..71ea252ed6 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
@@ -40,6 +40,7 @@ import org.apache.dubbo.config.utils.ConfigValidationUtils;
 import org.apache.dubbo.metadata.ServiceNameMapping;
 import org.apache.dubbo.metrics.event.MetricsEventBus;
 import org.apache.dubbo.metrics.event.MetricsInitEvent;
+import org.apache.dubbo.metrics.model.MethodMetric;
 import org.apache.dubbo.registry.client.metadata.MetadataUtils;
 import org.apache.dubbo.rpc.Exporter;
 import org.apache.dubbo.rpc.Invoker;
@@ -556,11 +557,12 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
     }
 
     private void initServiceMethodMetrics(URL url) {
-        String [] methods = Optional.ofNullable(url.getParameter(METHODS_KEY)).map(i->i.split(",")).orElse( new String[]{});
-        Arrays.stream(methods).forEach( method-> {
-            RpcInvocation invocation = new RpcInvocation(url.getServiceKey(),url.getServiceModel(),method,interfaceName, url.getProtocolServiceKey(), null, null,null,null,null,null);
-            MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(application.getApplicationModel(),invocation));
-            });
+        String[] methods = Optional.ofNullable(url.getParameter(METHODS_KEY)).map(i -> i.split(",")).orElse(new String[]{});
+        boolean serviceLevel = MethodMetric.isServiceLevel(application.getApplicationModel());
+        Arrays.stream(methods).forEach(method -> {
+            RpcInvocation invocation = new RpcInvocation(url.getServiceKey(), url.getServiceModel(), method, interfaceName, url.getProtocolServiceKey(), null, null, null, null, null, null);
+            MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(application.getApplicationModel(), invocation, serviceLevel));
+        });
     }
 
     private void processServiceExecutor(URL url) {
diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
index 01b0ca0267..411f55a3c4 100644
--- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
+++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd
@@ -1114,6 +1114,11 @@
                 <xsd:documentation><![CDATA[ Enable record rpc metrics. ]]></xsd:documentation>
             </xsd:annotation>
         </xsd:attribute>
+        <xsd:attribute name="rpc-level" type="xsd:string">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Is the metric for rpc requests at the METHOD level or SERVICE level ]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
     </xsd:complexType>
 
     <xsd:complexType name="tracingType">
diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/MethodStatComposite.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/MethodStatComposite.java
index d6cba3ee50..06cd8ade6e 100644
--- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/MethodStatComposite.java
+++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/MethodStatComposite.java
@@ -41,9 +41,11 @@ import java.util.concurrent.atomic.AtomicLong;
  * the key will not be displayed when exporting (to be optimized)
  */
 public class MethodStatComposite extends AbstractMetricsExport {
+    private boolean serviceLevel;
 
     public MethodStatComposite(ApplicationModel applicationModel) {
         super(applicationModel);
+        this.serviceLevel = MethodMetric.isServiceLevel(getApplicationModel());
     }
 
     private final Map<MetricsKeyWrapper, Map<MethodMetric, AtomicLong>> methodNumStats = new ConcurrentHashMap<>();
@@ -59,7 +61,8 @@ public class MethodStatComposite extends AbstractMetricsExport {
         if (!methodNumStats.containsKey(wrapper)) {
             return;
         }
-        methodNumStats.get(wrapper).computeIfAbsent(new MethodMetric(getApplicationModel(), invocation), k -> new AtomicLong(0L));
+
+        methodNumStats.get(wrapper).computeIfAbsent(new MethodMetric(getApplicationModel(), invocation, serviceLevel), k -> new AtomicLong(0L));
     }
 
     public void incrementMethodKey(MetricsKeyWrapper wrapper, MethodMetric methodMetric, int size) {
diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/RtStatComposite.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/RtStatComposite.java
index e6d0bae6e7..d335c0dfba 100644
--- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/RtStatComposite.java
+++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/RtStatComposite.java
@@ -50,9 +50,11 @@ import java.util.stream.Collectors;
  */
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class RtStatComposite extends AbstractMetricsExport {
+    private boolean serviceLevel;
 
     public RtStatComposite(ApplicationModel applicationModel) {
         super(applicationModel);
+        this.serviceLevel = MethodMetric.isServiceLevel(getApplicationModel());
     }
 
     private final Map<String, List<LongContainer<? extends Number>>> rtStats = new ConcurrentHashMap<>();
@@ -168,7 +170,7 @@ public class RtStatComposite extends AbstractMetricsExport {
         List<Action> actions;
         actions = new LinkedList<>();
         for (LongContainer container : rtStats.get(registryOpType)) {
-            MethodMetric key = new MethodMetric(getApplicationModel(), invocation);
+            MethodMetric key = new MethodMetric(getApplicationModel(), invocation, serviceLevel);
             Number current = (Number) container.get(key);
             if (current == null) {
                 container.putIfAbsent(key, container.getInitFunc().apply(key));
diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsInitEvent.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsInitEvent.java
index 8a1d1a8a62..bb01c88d7e 100644
--- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsInitEvent.java
+++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsInitEvent.java
@@ -34,8 +34,8 @@ public class MetricsInitEvent extends TimeCounterEvent {
         super(source,typeWrapper);
     }
 
-    public static MetricsInitEvent toMetricsInitEvent(ApplicationModel applicationModel, Invocation invocation) {
-        MethodMetric methodMetric = new MethodMetric(applicationModel, invocation);
+    public static MetricsInitEvent toMetricsInitEvent(ApplicationModel applicationModel, Invocation invocation, boolean serviceLevel) {
+        MethodMetric methodMetric = new MethodMetric(applicationModel, invocation, serviceLevel);
         MetricsInitEvent initEvent = new MetricsInitEvent(applicationModel, METRIC_EVENT);
         initEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
         initEvent.putAttachment(MetricsConstants.METHOD_METRICS, methodMetric);
diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MethodMetric.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MethodMetric.java
index c376fdd57d..6f4ddfffcf 100644
--- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MethodMetric.java
+++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MethodMetric.java
@@ -17,12 +17,17 @@
 
 package org.apache.dubbo.metrics.model;
 
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.config.MetricsConfig;
+import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.metrics.model.key.MetricsLevel;
 import org.apache.dubbo.rpc.Invocation;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.support.RpcUtils;
 
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 
 import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;
 import static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY;
@@ -36,12 +41,31 @@ public class MethodMetric extends ServiceKeyMetric {
     private String group;
     private String version;
 
-    public MethodMetric(ApplicationModel applicationModel, Invocation invocation) {
+
+    public MethodMetric(ApplicationModel applicationModel, Invocation invocation, boolean serviceLevel) {
         super(applicationModel, MetricsSupport.getInterfaceName(invocation));
-        this.methodName = RpcUtils.getMethodName(invocation);
         this.side = MetricsSupport.getSide(invocation);
         this.group = MetricsSupport.getGroup(invocation);
         this.version = MetricsSupport.getVersion(invocation);
+        this.methodName = serviceLevel ? null : RpcUtils.getMethodName(invocation);
+    }
+
+
+    public static boolean isServiceLevel(ApplicationModel applicationModel) {
+        if(applicationModel == null){
+            return false;
+        }
+        ConfigManager applicationConfigManager = applicationModel.getApplicationConfigManager();
+        if (applicationConfigManager == null) {
+            return false;
+        }
+        Optional<MetricsConfig> metrics = applicationConfigManager.getMetrics();
+        if (!metrics.isPresent()) {
+            return false;
+        }
+        String rpcLevel = metrics.map(MetricsConfig::getRpcLevel).orElse(MetricsLevel.METHOD.name());
+        rpcLevel = StringUtils.isBlank(rpcLevel) ? MetricsLevel.METHOD.name() : rpcLevel;
+        return MetricsLevel.SERVICE.name().equalsIgnoreCase(rpcLevel);
     }
 
     public String getGroup() {
@@ -82,13 +106,13 @@ public class MethodMetric extends ServiceKeyMetric {
     @Override
     public String toString() {
         return "MethodMetric{" +
-                "applicationName='" + getApplicationName() + '\'' +
-                ", side='" + side + '\'' +
-                ", interfaceName='" + getServiceKey() + '\'' +
-                ", methodName='" + methodName + '\'' +
-                ", group='" + group + '\'' +
-                ", version='" + version + '\'' +
-                '}';
+            "applicationName='" + getApplicationName() + '\'' +
+            ", side='" + side + '\'' +
+            ", interfaceName='" + getServiceKey() + '\'' +
+            ", methodName='" + methodName + '\'' +
+            ", group='" + group + '\'' +
+            ", version='" + version + '\'' +
+            '}';
     }
 
     @Override
@@ -100,6 +124,7 @@ public class MethodMetric extends ServiceKeyMetric {
     }
 
     private volatile int hashCode = 0;
+
     @Override
     public int hashCode() {
         if (hashCode == 0) {
diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollector.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollector.java
index ff7abf5d3c..7dc9117af5 100644
--- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollector.java
+++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollector.java
@@ -56,7 +56,7 @@ import static org.apache.dubbo.metrics.model.MetricsCategory.RT;
  * Aggregation metrics collector implementation of {@link MetricsCollector}.
  * This collector only enabled when metrics aggregation config is enabled.
  */
-public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>{
+public class AggregateMetricsCollector implements MetricsCollector<RequestEvent> {
     private int bucketNum = DEFAULT_BUCKET_NUM;
     private int timeWindowSeconds = DEFAULT_TIME_WINDOW_SECONDS;
     private int qpsTimeWindowMillSeconds = DEFAULT_QPS_TIME_WINDOW_MILL_SECONDS;
@@ -76,6 +76,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
 
     private final ConcurrentMap<MethodMetric, TimeWindowAggregator> rtAgr = new ConcurrentHashMap<>();
 
+    private boolean serviceLevel;
 
     public AggregateMetricsCollector(ApplicationModel applicationModel) {
         this.applicationModel = applicationModel;
@@ -96,6 +97,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
                 this.enableRt = Optional.ofNullable(aggregation.getEnableRt()).orElse(true);
                 this.enableRequest = Optional.ofNullable(aggregation.getEnableRequest()).orElse(true);
             }
+            this.serviceLevel = MethodMetric.isServiceLevel(applicationModel);
         }
     }
 
@@ -157,7 +159,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
     }
 
     private void onRTEvent(RequestEvent event) {
-        MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION));
+        MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
         long responseTime = event.getTimePair().calc();
         if (enableRt) {
             TimeWindowQuantile quantile = ConcurrentHashMapUtils.computeIfAbsent(rt, metric,
@@ -176,7 +178,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
     private MethodMetric calcWindowCounter(RequestEvent event, MetricsKey targetKey) {
         MetricsPlaceValue placeType = MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.SERVICE);
         MetricsKeyWrapper metricsKeyWrapper = new MetricsKeyWrapper(targetKey, placeType);
-        MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION));
+        MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
 
         ConcurrentMap<MethodMetric, TimeWindowCounter> counter = methodTypeCounter.computeIfAbsent(metricsKeyWrapper, k -> new ConcurrentHashMap<>());
 
@@ -189,7 +191,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
     @Override
     public List<MetricSample> collect() {
         List<MetricSample> list = new ArrayList<>();
-        if (!isCollectEnabled()){
+        if (!isCollectEnabled()) {
             return list;
         }
         collectRequests(list);
@@ -266,7 +268,7 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
 
     @Override
     public void initMetrics(MetricsEvent event) {
-        MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION));
+        MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
         if (enableQps) {
             initMethodMetric(event);
             initQpsMetric(metric);
@@ -279,27 +281,27 @@ public class AggregateMetricsCollector implements MetricsCollector<RequestEvent>
         }
     }
 
-    public void initMethodMetric(MetricsEvent event){
-        INIT_AGG_METHOD_KEYS.stream().forEach(key->initWindowCounter(event,key));
+    public void initMethodMetric(MetricsEvent event) {
+        INIT_AGG_METHOD_KEYS.stream().forEach(key -> initWindowCounter(event, key));
     }
 
-    public void initQpsMetric(MethodMetric metric){
+    public void initQpsMetric(MethodMetric metric) {
         ConcurrentHashMapUtils.computeIfAbsent(qps, metric, methodMetric -> new TimeWindowCounter(bucketNum, timeWindowSeconds));
     }
 
-    public void initRtMetric(MethodMetric metric){
+    public void initRtMetric(MethodMetric metric) {
         ConcurrentHashMapUtils.computeIfAbsent(rt, metric, k -> new TimeWindowQuantile(DEFAULT_COMPRESSION, bucketNum, timeWindowSeconds));
     }
 
-    public void initRtAgrMetric(MethodMetric metric){
+    public void initRtAgrMetric(MethodMetric metric) {
         ConcurrentHashMapUtils.computeIfAbsent(rtAgr, metric, k -> new TimeWindowAggregator(bucketNum, timeWindowSeconds));
     }
 
-    public void initWindowCounter(MetricsEvent event, MetricsKey targetKey){
+    public void initWindowCounter(MetricsEvent event, MetricsKey targetKey) {
 
         MetricsKeyWrapper metricsKeyWrapper = new MetricsKeyWrapper(targetKey, MetricsPlaceValue.of(event.getAttachmentValue(MetricsConstants.INVOCATION_SIDE), MetricsLevel.SERVICE));
 
-        MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION));
+        MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
 
         ConcurrentMap<MethodMetric, TimeWindowCounter> counter = methodTypeCounter.computeIfAbsent(metricsKeyWrapper, k -> new ConcurrentHashMap<>());
 
diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/HistogramMetricsCollector.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/HistogramMetricsCollector.java
index 872f77df1a..932c285d8e 100644
--- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/HistogramMetricsCollector.java
+++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/HistogramMetricsCollector.java
@@ -48,6 +48,8 @@ public class HistogramMetricsCollector extends AbstractMetricsListener<RequestEv
 
     private static final Integer[] DEFAULT_BUCKETS_MS = new Integer[]{100, 300, 500, 1000, 3000, 5000, 10000};
 
+    private boolean serviceLevel;
+
     public HistogramMetricsCollector(ApplicationModel applicationModel) {
         this.applicationModel = applicationModel;
 
@@ -68,6 +70,7 @@ public class HistogramMetricsCollector extends AbstractMetricsListener<RequestEv
             }
 
             metricRegister = new HistogramMetricRegister(MetricsGlobalRegistry.getCompositeRegistry(applicationModel), histogram);
+            this.serviceLevel = MethodMetric.isServiceLevel(applicationModel);
         }
     }
 
@@ -92,7 +95,7 @@ public class HistogramMetricsCollector extends AbstractMetricsListener<RequestEv
 
     private void onRTEvent(RequestEvent event) {
         if (metricRegister != null) {
-            MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION));
+            MethodMetric metric = new MethodMetric(applicationModel, event.getAttachmentValue(MetricsConstants.INVOCATION), serviceLevel);
             long responseTime = event.getTimePair().calc();
 
             HistogramMetricSample sample = new HistogramMetricSample(MetricsKey.METRIC_RT_HISTOGRAM.getNameByType(metric.getSide()),
diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/RequestEvent.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/RequestEvent.java
index 93ad680df1..4773ce158a 100644
--- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/RequestEvent.java
+++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/RequestEvent.java
@@ -56,8 +56,8 @@ public class RequestEvent extends TimeCounterEvent {
 
     public static RequestEvent toRequestEvent(ApplicationModel applicationModel, String appName,
                                               MetricsDispatcher metricsDispatcher, DefaultMetricsCollector collector,
-                                              Invocation invocation, String side) {
-        MethodMetric methodMetric = new MethodMetric(applicationModel, invocation);
+                                              Invocation invocation, String side, boolean serviceLevel) {
+        MethodMetric methodMetric = new MethodMetric(applicationModel, invocation, serviceLevel);
         RequestEvent requestEvent = new RequestEvent(applicationModel, appName, metricsDispatcher, collector, REQUEST_EVENT);
         requestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
         requestEvent.putAttachment(MetricsConstants.METHOD_METRICS, methodMetric);
@@ -80,13 +80,13 @@ public class RequestEvent extends TimeCounterEvent {
     /**
      * Acts on MetricsClusterFilter to monitor exceptions that occur before request execution
      */
-    public static RequestEvent toRequestErrorEvent(ApplicationModel applicationModel, String appName, MetricsDispatcher metricsDispatcher, Invocation invocation, String side, int code) {
+    public static RequestEvent toRequestErrorEvent(ApplicationModel applicationModel, String appName, MetricsDispatcher metricsDispatcher, Invocation invocation, String side, int code, boolean serviceLevel) {
         RequestEvent event = new RequestEvent(applicationModel, appName, metricsDispatcher, null,  REQUEST_ERROR_EVENT);
         event.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));
         event.putAttachment(MetricsConstants.INVOCATION_SIDE, side);
         event.putAttachment(MetricsConstants.INVOCATION, invocation);
         event.putAttachment(MetricsConstants.INVOCATION_REQUEST_ERROR, code);
-        event.putAttachment(MetricsConstants.METHOD_METRICS, new MethodMetric(applicationModel, invocation));
+        event.putAttachment(MetricsConstants.METHOD_METRICS, new MethodMetric(applicationModel, invocation, serviceLevel));
         return event;
     }
 
diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/filter/MetricsFilter.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/filter/MetricsFilter.java
index 2492b78b70..0496443732 100644
--- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/filter/MetricsFilter.java
+++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/filter/MetricsFilter.java
@@ -23,6 +23,7 @@ import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
 import org.apache.dubbo.metrics.event.MetricsDispatcher;
 import org.apache.dubbo.metrics.event.MetricsEventBus;
 import org.apache.dubbo.metrics.event.RequestEvent;
+import org.apache.dubbo.metrics.model.MethodMetric;
 import org.apache.dubbo.metrics.model.MetricsSupport;
 import org.apache.dubbo.rpc.Invocation;
 import org.apache.dubbo.rpc.Invoker;
@@ -45,6 +46,7 @@ public class MetricsFilter implements ScopeModelAware {
     private String appName;
     private MetricsDispatcher metricsDispatcher;
     private DefaultMetricsCollector defaultMetricsCollector;
+    private boolean serviceLevel;
 
     @Override
     public void setApplicationModel(ApplicationModel applicationModel) {
@@ -53,6 +55,7 @@ public class MetricsFilter implements ScopeModelAware {
         this.appName = applicationModel.tryGetApplicationName();
         this.metricsDispatcher = applicationModel.getBeanFactory().getBean(MetricsDispatcher.class);
         this.defaultMetricsCollector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
+        serviceLevel = MethodMetric.isServiceLevel(applicationModel);
     }
 
     public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
@@ -63,7 +66,7 @@ public class MetricsFilter implements ScopeModelAware {
         if (rpcMetricsEnable) {
             try {
                 RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, appName, metricsDispatcher,
-                    defaultMetricsCollector, invocation, isProvider ? PROVIDER : CONSUMER);
+                    defaultMetricsCollector, invocation, isProvider ? PROVIDER : CONSUMER, serviceLevel);
                 MetricsEventBus.before(requestEvent);
                 invocation.put(METRIC_FILTER_EVENT, requestEvent);
             } catch (Throwable t) {
diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java
index 652d335ab8..ce34ce01fd 100644
--- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java
+++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java
@@ -38,7 +38,6 @@ import org.apache.dubbo.metrics.model.MethodMetric;
 import org.apache.dubbo.metrics.model.MetricsSupport;
 import org.apache.dubbo.metrics.model.TimePair;
 import org.apache.dubbo.metrics.model.key.MetricsKey;
-import org.apache.dubbo.metrics.model.key.MetricsLevel;
 import org.apache.dubbo.metrics.model.key.TypeWrapper;
 import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
 import org.apache.dubbo.metrics.model.sample.MetricSample;
@@ -90,7 +89,7 @@ class AggregateMetricsCollectorTest {
 
     public MethodMetric getTestMethodMetric() {
 
-        MethodMetric methodMetric = new MethodMetric(applicationModel, invocation);
+        MethodMetric methodMetric = new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel));
         methodMetric.setGroup("TestGroup");
         methodMetric.setVersion("1.0.0");
         methodMetric.setSide("PROVIDER");
@@ -141,8 +140,8 @@ class AggregateMetricsCollectorTest {
     @Test
     void testListener() {
         AggregateMetricsCollector metricsCollector = new AggregateMetricsCollector(applicationModel);
-        RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation));
-        RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION);
+        RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel));
+        RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION, MethodMetric.isServiceLevel(applicationModel));
 
         Assertions.assertTrue(metricsCollector.isSupport(event));
         Assertions.assertTrue(metricsCollector.isSupport(beforeEvent));
@@ -200,7 +199,8 @@ class AggregateMetricsCollectorTest {
 
         when(applicationModel.getApplicationConfigManager()).thenReturn(configManager);
         when(applicationModel.getBeanFactory()).thenReturn(beanFactory);
-        when(beanFactory.getBean(DefaultMetricsCollector.class)).thenReturn(new DefaultMetricsCollector(applicationModel));
+        DefaultMetricsCollector defaultMetricsCollector = new DefaultMetricsCollector(applicationModel);
+        when(beanFactory.getBean(DefaultMetricsCollector.class)).thenReturn(defaultMetricsCollector);
         when(configManager.getMetrics()).thenReturn(Optional.of(metricsConfig));
         when(metricsConfig.getAggregation()).thenReturn(aggregationConfig);
         when(aggregationConfig.getEnabled()).thenReturn(Boolean.TRUE);
@@ -249,7 +249,7 @@ class AggregateMetricsCollectorTest {
         rtList.add(30L);
 
         for (Long requestTime: rtList) {
-            RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation));
+            RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel));
             TestRequestEvent testRequestEvent = new TestRequestEvent(requestEvent.getSource(), requestEvent.getTypeWrapper());
             testRequestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
             testRequestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));
@@ -299,7 +299,7 @@ class AggregateMetricsCollectorTest {
         double manualP99 = requestTimes.get((int) Math.round(p99Index));
 
         for (Long requestTime : requestTimes) {
-            RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation));
+            RequestEvent requestEvent = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel));
             TestRequestEvent testRequestEvent = new TestRequestEvent(requestEvent.getSource(), requestEvent.getTypeWrapper());
             testRequestEvent.putAttachment(MetricsConstants.INVOCATION, invocation);
             testRequestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation));
diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java
index 450da8a7c6..88fac20a70 100644
--- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java
+++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java
@@ -24,13 +24,13 @@ import org.apache.dubbo.metrics.TestMetricsInvoker;
 import org.apache.dubbo.metrics.event.MetricsDispatcher;
 import org.apache.dubbo.metrics.event.RequestEvent;
 import org.apache.dubbo.metrics.filter.MetricsFilter;
+import org.apache.dubbo.metrics.model.MethodMetric;
 import org.apache.dubbo.metrics.model.MetricsSupport;
 import org.apache.dubbo.metrics.model.ServiceKeyMetric;
 import org.apache.dubbo.metrics.model.key.MetricsKey;
 import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
 import org.apache.dubbo.metrics.model.key.MetricsLevel;
 import org.apache.dubbo.metrics.model.key.MetricsPlaceValue;
-import org.apache.dubbo.metrics.model.key.TypeWrapper;
 import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
 import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
 import org.apache.dubbo.metrics.model.sample.MetricSample;
@@ -112,8 +112,8 @@ class DefaultCollectorTest {
     @Test
     void testListener() {
         DefaultMetricsCollector metricsCollector = new DefaultMetricsCollector(applicationModel);
-        RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation));
-        RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION);
+        RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation), MethodMetric.isServiceLevel(applicationModel));
+        RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION, MethodMetric.isServiceLevel(applicationModel));
 
         Assertions.assertTrue(metricsCollector.isSupport(event));
         Assertions.assertTrue(metricsCollector.isSupport(beforeEvent));
diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/InitServiceMetricsTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/InitServiceMetricsTest.java
index 0db777732e..eff1d0bc8f 100644
--- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/InitServiceMetricsTest.java
+++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/InitServiceMetricsTest.java
@@ -23,6 +23,7 @@ import org.apache.dubbo.config.nested.AggregationConfig;
 import org.apache.dubbo.metrics.aggregate.TimeWindowCounter;
 import org.apache.dubbo.metrics.event.MetricsEventBus;
 import org.apache.dubbo.metrics.event.MetricsInitEvent;
+import org.apache.dubbo.metrics.model.MethodMetric;
 import org.apache.dubbo.metrics.model.ServiceKeyMetric;
 import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper;
 import org.apache.dubbo.metrics.model.key.MetricsLevel;
@@ -96,7 +97,7 @@ class InitServiceMetricsTest {
         String protocolServiceKey=serviceKey+":dubbo";
 
         RpcInvocation invocation = new RpcInvocation(serviceKey,null,methodName,interfaceName, protocolServiceKey, null, null,null,null,null,null);
-        MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(applicationModel,invocation));
+        MetricsEventBus.publish(MetricsInitEvent.toMetricsInitEvent(applicationModel,invocation, MethodMetric.isServiceLevel(applicationModel)));
 
     }
 
diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/MethodMetricTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/MethodMetricTest.java
index 38da8bd843..d894f15a5d 100644
--- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/MethodMetricTest.java
+++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/MethodMetricTest.java
@@ -19,7 +19,9 @@ package org.apache.dubbo.metrics.metrics.model;
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.MetricsConfig;
 import org.apache.dubbo.metrics.model.MethodMetric;
+import org.apache.dubbo.metrics.model.key.MetricsLevel;
 import org.apache.dubbo.rpc.RpcContext;
 import org.apache.dubbo.rpc.RpcInvocation;
 import org.apache.dubbo.rpc.model.ApplicationModel;
@@ -72,7 +74,7 @@ class MethodMetricTest {
 
     @Test
     void test() {
-        MethodMetric metric = new MethodMetric(applicationModel, invocation);
+        MethodMetric metric = new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel));
         Assertions.assertEquals(metric.getServiceKey(), interfaceName);
         Assertions.assertEquals(metric.getMethodName(), methodName);
         Assertions.assertEquals(metric.getGroup(), group);
@@ -88,4 +90,24 @@ class MethodMetricTest {
         Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group);
         Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version);
     }
+
+    @Test
+    void testServiceMetrics() {
+        MetricsConfig metricConfig = new MetricsConfig();
+        applicationModel.getApplicationConfigManager().setMetrics(metricConfig);
+        metricConfig.setRpcLevel(MetricsLevel.SERVICE.name());
+        MethodMetric metric = new MethodMetric(applicationModel, invocation, MethodMetric.isServiceLevel(applicationModel));
+        Assertions.assertEquals(metric.getServiceKey(), interfaceName);
+        Assertions.assertNull(metric.getMethodName(), methodName);
+        Assertions.assertEquals(metric.getGroup(), group);
+        Assertions.assertEquals(metric.getVersion(), version);
+
+        Map<String, String> tags = metric.getTags();
+        Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationModel.getApplicationName());
+
+        Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName);
+        Assertions.assertNull(tags.get(TAG_METHOD_KEY));
+        Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group);
+        Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version);
+    }
 }