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 6faf548e24 Add histogram (#11632)
6faf548e24 is described below

commit 6faf548e2463693e70274015bc8d11d624c12f19
Author: gsralex <[email protected]>
AuthorDate: Mon Mar 27 09:49:09 2023 +0800

    Add histogram (#11632)
---
 .../dubbo/common/constants/MetricsConstants.java   |  2 +
 .../org/apache/dubbo/config/MetricsConfig.java     | 12 +++
 .../dubbo/config/nested/HistogramConfig.java       | 93 ++++++++++++++++++++++
 .../org/apache/dubbo/config/MetricsConfigTest.java |  9 ++-
 .../spring/schema/DubboBeanDefinitionParser.java   |  5 ++
 .../src/main/resources/META-INF/dubbo.xsd          | 15 ++++
 .../configprops/SpringBootConfigPropsTest.java     |  4 +-
 .../SpringBootMultipleConfigPropsTest.java         |  4 +-
 .../metrics/SpringBootConfigMetricsTest.java       |  2 +
 .../org/apache/dubbo/metrics/model/MetricsKey.java |  6 ++
 .../org/apache/dubbo/metrics/DubboMetrics.java     |  3 +-
 ...ubboMetrics.java => MetricsGlobalRegistry.java} | 22 ++---
 .../collector/HistogramMetricsCollector.java       | 88 ++++++++++++++++++++
 .../metrics/register/HistogramMetricRegister.java  | 81 +++++++++++++++++++
 .../MetricRegister.java}                           | 24 ++----
 .../metrics/report/AbstractMetricsReporter.java    |  6 +-
 .../HistogramMetricSample.java}                    | 25 +++---
 17 files changed, 342 insertions(+), 59 deletions(-)

diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java
index 58b6b39887..b41e716bd2 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java
@@ -54,6 +54,8 @@ public interface MetricsConstants {
 
     String AGGREGATION_TIME_WINDOW_SECONDS_KEY = 
"aggregation.time.window.seconds";
 
+    String HISTOGRAM_ENABLED_KEY = "histogram.enabled";
+
     String PROMETHEUS_EXPORTER_ENABLED_KEY = "prometheus.exporter.enabled";
 
     String PROMETHEUS_EXPORTER_ENABLE_HTTP_SERVICE_DISCOVERY_KEY = 
"prometheus.exporter.enable.http.service.discovery";
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 07a1e5f425..d915f53d6b 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
@@ -20,6 +20,7 @@ import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.utils.UrlUtils;
 import org.apache.dubbo.config.nested.AggregationConfig;
 import org.apache.dubbo.config.nested.PrometheusConfig;
+import org.apache.dubbo.config.nested.HistogramConfig;
 import org.apache.dubbo.config.support.Nested;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 
@@ -69,6 +70,9 @@ public class MetricsConfig extends AbstractConfig {
     @Nested
     private AggregationConfig aggregation;
 
+    @Nested
+    private HistogramConfig histogram;
+
     private String exportServiceProtocol;
 
     private Integer exportServicePort;
@@ -140,6 +144,14 @@ public class MetricsConfig extends AbstractConfig {
         this.aggregation = aggregation;
     }
 
+    public HistogramConfig getHistogram() {
+        return histogram;
+    }
+
+    public void setHistogram(HistogramConfig histogram) {
+        this.histogram = histogram;
+    }
+
     public String getExportServiceProtocol() {
         return exportServiceProtocol;
     }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/HistogramConfig.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/HistogramConfig.java
new file mode 100644
index 0000000000..53ef9ac9e4
--- /dev/null
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/HistogramConfig.java
@@ -0,0 +1,93 @@
+/*
+ * 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.config.nested;
+
+import java.io.Serializable;
+
+public class HistogramConfig implements Serializable {
+
+    private Boolean enabled;
+
+    private Integer[] bucketsMs;
+
+    private Integer minExpectedMs;
+
+    private Integer maxExpectedMs;
+
+    private Boolean enabledPercentiles;
+
+    private double[] percentiles;
+
+    private Integer distributionStatisticExpiryMin;
+
+    public Boolean getEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(Boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    public Integer[] getBucketsMs() {
+        return bucketsMs;
+    }
+
+    public void setBucketsMs(Integer[] bucketsMs) {
+        this.bucketsMs = bucketsMs;
+    }
+
+    public Integer getMinExpectedMs() {
+        return minExpectedMs;
+    }
+
+    public void setMinExpectedMs(Integer minExpectedMs) {
+        this.minExpectedMs = minExpectedMs;
+    }
+
+    public Integer getMaxExpectedMs() {
+        return maxExpectedMs;
+    }
+
+    public void setMaxExpectedMs(Integer maxExpectedMs) {
+        this.maxExpectedMs = maxExpectedMs;
+    }
+
+    public Boolean getEnabledPercentiles() {
+        return enabledPercentiles;
+    }
+
+    public void setEnabledPercentiles(Boolean enabledPercentiles) {
+        this.enabledPercentiles = enabledPercentiles;
+    }
+
+    public double[] getPercentiles() {
+        return percentiles;
+    }
+
+    public void setPercentiles(double[] percentiles) {
+        this.percentiles = percentiles;
+    }
+
+    public Integer getDistributionStatisticExpiryMin() {
+        return distributionStatisticExpiryMin;
+    }
+
+    public void setDistributionStatisticExpiryMin(Integer 
distributionStatisticExpiryMin) {
+        this.distributionStatisticExpiryMin = distributionStatisticExpiryMin;
+    }
+}
diff --git 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MetricsConfigTest.java
 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MetricsConfigTest.java
index f752b7e86c..13a29b8966 100644
--- 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MetricsConfigTest.java
+++ 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/MetricsConfigTest.java
@@ -19,7 +19,7 @@ package org.apache.dubbo.config;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.config.nested.AggregationConfig;
 import org.apache.dubbo.config.nested.PrometheusConfig;
-
+import org.apache.dubbo.config.nested.HistogramConfig;
 import org.junit.jupiter.api.Test;
 
 import static 
org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;
@@ -47,6 +47,10 @@ class MetricsConfigTest {
         aggregation.setEnabled(true);
         metrics.setAggregation(aggregation);
 
+        HistogramConfig histogram = new HistogramConfig();
+        histogram.setEnabled(true);
+        metrics.setHistogram(histogram);
+
         URL url = metrics.toUrl();
 
         assertThat(url.getProtocol(), equalTo(PROTOCOL_PROMETHEUS));
@@ -56,6 +60,7 @@ class MetricsConfigTest {
         assertThat(url.getParameter("prometheus.exporter.enabled"), 
equalTo("true"));
         assertThat(url.getParameter("prometheus.pushgateway.enabled"), 
equalTo("true"));
         assertThat(url.getParameter("aggregation.enabled"), equalTo("true"));
+        assertThat(url.getParameter("histogram.enabled"), equalTo("true"));
     }
 
     @Test
@@ -117,4 +122,4 @@ class MetricsConfigTest {
         assertThat(metrics.getAggregation().getBucketNum(), equalTo(5));
         assertThat(metrics.getAggregation().getTimeWindowSeconds(), 
equalTo(120));
     }
-}
\ No newline at end of file
+}
diff --git 
a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
 
b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
index 832c91f0c4..8f63565b21 100644
--- 
a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
+++ 
b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java
@@ -33,6 +33,7 @@ import org.apache.dubbo.config.ReferenceConfig;
 import org.apache.dubbo.config.RegistryConfig;
 import org.apache.dubbo.config.nested.AggregationConfig;
 import org.apache.dubbo.config.nested.PrometheusConfig;
+import org.apache.dubbo.config.nested.HistogramConfig;
 import org.apache.dubbo.config.spring.Constants;
 import org.apache.dubbo.config.spring.ReferenceBean;
 import org.apache.dubbo.config.spring.ServiceBean;
@@ -265,6 +266,10 @@ public class DubboBeanDefinitionParser implements 
BeanDefinitionParser {
                 AggregationConfig aggregation = new AggregationConfig();
                 assignProperties(aggregation, child, parserContext);
                 
beanDefinition.getPropertyValues().addPropertyValue("aggregation", aggregation);
+            }else if("histogram".equals(child.getNodeName()) || 
"histogram".equals(child.getLocalName())){
+                HistogramConfig histogram = new HistogramConfig();
+                assignProperties(histogram, child, parserContext);
+                
beanDefinition.getPropertyValues().addPropertyValue("histogram", histogram);
             } else if ("prometheus-exporter".equals(child.getNodeName()) || 
"prometheus-exporter".equals(child.getLocalName())) {
                 if (prometheus == null) {
                     prometheus = new PrometheusConfig();
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 d801ffefc3..e1f272f402 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
@@ -1044,6 +1044,7 @@
             <xsd:element ref="prometheus-exporter" minOccurs="0"/>
             <xsd:element ref="prometheus-pushgateway" minOccurs="0"/>
             <xsd:element ref="aggregation" minOccurs="0"/>
+            <xsd:element ref="histogram" minOccurs="0"/>
         </xsd:all>
         <xsd:attribute name="protocol" type="xsd:string">
             <xsd:annotation>
@@ -1155,6 +1156,14 @@
         </xsd:attribute>
     </xsd:complexType>
 
+    <xsd:complexType name="histogramType">
+        <xsd:attribute name="enabled" type="xsd:boolean">
+            <xsd:annotation>
+                <xsd:documentation><![CDATA[ Enable local rt histogram or not. 
]]></xsd:documentation>
+            </xsd:annotation>
+        </xsd:attribute>
+    </xsd:complexType>
+
     <xsd:complexType name="methodType">
         <xsd:complexContent>
             <xsd:extension base="abstractMethodType">
@@ -2045,4 +2054,10 @@
             <xsd:documentation><![CDATA[ The metrics aggregation config. 
]]></xsd:documentation>
         </xsd:annotation>
     </xsd:element>
+
+    <xsd:element name="histogram" type="histogramType">
+        <xsd:annotation>
+            <xsd:documentation><![CDATA[ The metrics rt histogram config. 
]]></xsd:documentation>
+        </xsd:annotation>
+    </xsd:element>
 </xsd:schema>
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java
 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java
index 9ce1a7f5aa..2eaa56b828 100644
--- 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java
+++ 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootConfigPropsTest.java
@@ -64,6 +64,7 @@ import static 
org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMET
         "dubbo.metrics.aggregation.enabled=true",
         "dubbo.metrics.aggregation.bucket-num=5",
         "dubbo.metrics.aggregation.time-window-seconds=120",
+        "dubbo.metrics.histogram.enabled=true",
         "dubbo.monitor.address=zookeeper://127.0.0.1:32770",
         "dubbo.Config-center.address=${zookeeper.connection.address.1}",
         "dubbo.config-Center.group=group1",
@@ -116,6 +117,7 @@ class SpringBootConfigPropsTest {
         Assertions.assertEquals(5, 
metricsConfig.getAggregation().getBucketNum());
         Assertions.assertEquals(120, 
metricsConfig.getAggregation().getTimeWindowSeconds());
         Assertions.assertTrue(metricsConfig.getAggregation().getEnabled());
+        Assertions.assertTrue(metricsConfig.getHistogram().getEnabled());
 
         List<ProtocolConfig> defaultProtocols = 
configManager.getDefaultProtocols();
         Assertions.assertEquals(1, defaultProtocols.size());
@@ -153,4 +155,4 @@ class SpringBootConfigPropsTest {
 
     }
 
-}
\ No newline at end of file
+}
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
index 9bb31c119c..482cd054cd 100644
--- 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
+++ 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/boot/configprops/SpringBootMultipleConfigPropsTest.java
@@ -63,6 +63,7 @@ import static 
org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMET
         "dubbo.metricses.my-metrics.aggregation.enabled=true",
         "dubbo.metricses.my-metrics.aggregation.bucket-num=5",
         "dubbo.metricses.my-metrics.aggregation.time-window-seconds=120",
+        "dubbo.metricses.my-metrics.histogram.enabled=true",
         "dubbo.monitors.my-monitor.address=zookeeper://127.0.0.1:32770",
         
"dubbo.config-centers.my-configcenter.address=${zookeeper.connection.address.1}",
         "dubbo.config-centers.my-configcenter.group=group1",
@@ -116,6 +117,7 @@ class SpringBootMultipleConfigPropsTest {
         Assertions.assertEquals(5, 
metricsConfig.getAggregation().getBucketNum());
         Assertions.assertEquals(120, 
metricsConfig.getAggregation().getTimeWindowSeconds());
         Assertions.assertTrue(metricsConfig.getAggregation().getEnabled());
+        Assertions.assertTrue(metricsConfig.getHistogram().getEnabled());
 
         List<ProtocolConfig> defaultProtocols = 
configManager.getDefaultProtocols();
         Assertions.assertEquals(1, defaultProtocols.size());
@@ -154,4 +156,4 @@ class SpringBootMultipleConfigPropsTest {
 
     }
 
-}
\ No newline at end of file
+}
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/metrics/SpringBootConfigMetricsTest.java
 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/metrics/SpringBootConfigMetricsTest.java
index 3b54f09bd0..089e691af2 100644
--- 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/metrics/SpringBootConfigMetricsTest.java
+++ 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/metrics/SpringBootConfigMetricsTest.java
@@ -50,6 +50,7 @@ import org.springframework.context.annotation.Configuration;
         "dubbo.metrics.aggregation.enabled=true",
         "dubbo.metrics.aggregation.bucket-num=5",
         "dubbo.metrics.aggregation.time-window-seconds=120",
+        "dubbo.metrics.histogram.enabled=true",
         "dubbo.metadata-report.address=${zookeeper.connection.address.2}"
     },
     classes = {
@@ -90,6 +91,7 @@ public class SpringBootConfigMetricsTest {
         Assertions.assertEquals(5, 
metricsConfig.getAggregation().getBucketNum());
         Assertions.assertEquals(120, 
metricsConfig.getAggregation().getTimeWindowSeconds());
         Assertions.assertTrue(metricsConfig.getAggregation().getEnabled());
+        Assertions.assertTrue(metricsConfig.getHistogram().getEnabled());
     }
 
 }
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 6065ee5289..adc558ef9c 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
@@ -61,6 +61,12 @@ public enum MetricsKey {
     REGISTER_METRIC_REQUESTS("dubbo.registry.register.requests.total", "Total 
Register Requests"),
     
REGISTER_METRIC_REQUESTS_SUCCEED("dubbo.registry.register.requests.succeed.total",
 "Succeed Register Requests"),
     
REGISTER_METRIC_REQUESTS_FAILED("dubbo.registry.register.requests.failed.total",
 "Failed Register Requests"),
+    METRIC_RT_HISTOGRAM("dubbo.%s.rt.milliseconds.histogram", "Response Time 
Histogram"),
+
+
+    GENERIC_METRIC_REQUESTS("dubbo.%s.requests.total", "Total %s Requests"),
+    GENERIC_METRIC_REQUESTS_SUCCEED("dubbo.%s.requests.succeed.total", 
"Succeed %s Requests"),
+    GENERIC_METRIC_REQUESTS_FAILED("dubbo.%s.requests.failed.total", "Failed 
%s Requests"),
 
     // subscribe metrics key
     SUBSCRIBE_METRIC_NUM("dubbo.registry.subscribe.num.total", "Total 
Subscribe Num"),
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DubboMetrics.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DubboMetrics.java
index 00351aedcc..ab38c121a5 100644
--- 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DubboMetrics.java
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DubboMetrics.java
@@ -19,7 +19,6 @@ package org.apache.dubbo.metrics;
 import io.micrometer.core.instrument.MeterRegistry;
 import io.micrometer.core.instrument.binder.MeterBinder;
 import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
-import org.apache.dubbo.metrics.report.AbstractMetricsReporter;
 
 
 public class DubboMetrics implements MeterBinder {
@@ -29,7 +28,7 @@ public class DubboMetrics implements MeterBinder {
     @Override
     public void bindTo(MeterRegistry registry) {
         globalRegistry = registry;
-        CompositeMeterRegistry compositeRegistry = 
AbstractMetricsReporter.compositeRegistry;
+        CompositeMeterRegistry compositeRegistry = 
MetricsGlobalRegistry.getCompositeRegistry();
         if (compositeRegistry != null) {
             compositeRegistry.add(registry);
         }
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DubboMetrics.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsGlobalRegistry.java
similarity index 60%
copy from 
dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DubboMetrics.java
copy to 
dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsGlobalRegistry.java
index 00351aedcc..cc6c824c18 100644
--- 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DubboMetrics.java
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsGlobalRegistry.java
@@ -14,28 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.apache.dubbo.metrics;
 
-import io.micrometer.core.instrument.MeterRegistry;
-import io.micrometer.core.instrument.binder.MeterBinder;
 import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
-import org.apache.dubbo.metrics.report.AbstractMetricsReporter;
-
 
-public class DubboMetrics implements MeterBinder {
+public class MetricsGlobalRegistry {
 
-    private MeterRegistry globalRegistry = null;
+    private static final CompositeMeterRegistry compositeRegistry = new 
CompositeMeterRegistry();
 
-    @Override
-    public void bindTo(MeterRegistry registry) {
-        globalRegistry = registry;
-        CompositeMeterRegistry compositeRegistry = 
AbstractMetricsReporter.compositeRegistry;
-        if (compositeRegistry != null) {
-            compositeRegistry.add(registry);
-        }
-    }
-
-    public void destroy() {
+    public static CompositeMeterRegistry getCompositeRegistry() {
+        return compositeRegistry;
     }
 }
-
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
new file mode 100644
index 0000000000..9fc57059ac
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/HistogramMetricsCollector.java
@@ -0,0 +1,88 @@
+/*
+ * 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.collector;
+
+import io.micrometer.core.instrument.Timer;
+import org.apache.dubbo.common.utils.ConcurrentHashMapUtils;
+import org.apache.dubbo.config.MetricsConfig;
+import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.nested.HistogramConfig;
+import org.apache.dubbo.metrics.MetricsGlobalRegistry;
+import org.apache.dubbo.metrics.event.MetricsEvent;
+import org.apache.dubbo.metrics.event.RTEvent;
+import org.apache.dubbo.metrics.listener.MetricsListener;
+import org.apache.dubbo.metrics.model.MethodMetric;
+import org.apache.dubbo.metrics.model.MetricsKey;
+import org.apache.dubbo.metrics.register.HistogramMetricRegister;
+import org.apache.dubbo.metrics.sample.HistogramMetricSample;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.dubbo.metrics.model.MetricsCategory.RT;
+
+public class HistogramMetricsCollector implements MetricsListener {
+
+    private final ConcurrentHashMap<MethodMetric, Timer> rt = new 
ConcurrentHashMap<>();
+    private HistogramMetricRegister metricRegister;
+    private final ApplicationModel applicationModel;
+
+    private static final Integer[] DEFAULT_BUCKETS_MS = new Integer[]{100, 
300, 500, 1000, 3000, 5000, 10000};
+
+    public HistogramMetricsCollector(ApplicationModel applicationModel) {
+        this.applicationModel = applicationModel;
+
+        ConfigManager configManager = 
applicationModel.getApplicationConfigManager();
+        MetricsConfig config = configManager.getMetrics().orElse(null);
+        if (config != null && config.getHistogram() != null && 
Boolean.TRUE.equals(config.getHistogram().getEnabled())) {
+            registerListener();
+
+            HistogramConfig histogram = config.getHistogram();
+            if (!Boolean.TRUE.equals(histogram.getEnabledPercentiles()) && 
histogram.getBucketsMs() == null) {
+                histogram.setBucketsMs(DEFAULT_BUCKETS_MS);
+            }
+
+            metricRegister = new 
HistogramMetricRegister(MetricsGlobalRegistry.getCompositeRegistry(), 
histogram);
+        }
+    }
+
+    private void registerListener() {
+        
applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class).addListener(this);
+    }
+
+    @Override
+    public void onEvent(MetricsEvent event) {
+        if (event instanceof RTEvent) {
+            onRTEvent((RTEvent) event);
+        }
+    }
+
+    private void onRTEvent(RTEvent event) {
+        if (metricRegister != null) {
+            MethodMetric metric = (MethodMetric) event.getSource();
+            Long responseTime = event.getRt();
+
+            HistogramMetricSample sample = new 
HistogramMetricSample(MetricsKey.METRIC_RT_HISTOGRAM.getNameByType(metric.getSide()),
+                MetricsKey.METRIC_RT_HISTOGRAM.getDescription(), 
metric.getTags(), RT);
+
+            Timer timer = ConcurrentHashMapUtils.computeIfAbsent(rt, metric, k 
-> metricRegister.register(sample));
+            timer.record(responseTime, TimeUnit.MILLISECONDS);
+        }
+    }
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/register/HistogramMetricRegister.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/register/HistogramMetricRegister.java
new file mode 100644
index 0000000000..04a173cdee
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/register/HistogramMetricRegister.java
@@ -0,0 +1,81 @@
+/*
+ * 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.register;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Tag;
+import io.micrometer.core.instrument.Timer;
+import org.apache.dubbo.config.nested.HistogramConfig;
+import org.apache.dubbo.metrics.sample.HistogramMetricSample;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class HistogramMetricRegister implements 
MetricRegister<HistogramMetricSample, Timer> {
+
+    private final MeterRegistry registry;
+    private final HistogramConfig config;
+
+    public HistogramMetricRegister(MeterRegistry registry, HistogramConfig 
config) {
+        this.registry = registry;
+        this.config = config;
+    }
+
+    @Override
+    public Timer register(HistogramMetricSample sample) {
+        List<Tag> tags = new ArrayList<>();
+        sample.getTags().forEach((k, v) -> {
+            if (v == null) {
+                v = "";
+            }
+
+            tags.add(Tag.of(k, v));
+        });
+
+        Timer.Builder builder = 
Timer.builder(sample.getName()).description(sample.getDescription()).tags(tags);
+
+        if (Boolean.TRUE.equals(config.getEnabledPercentiles())) {
+            builder.publishPercentileHistogram(true);
+        }
+
+        if (config.getPercentiles() != null) {
+            builder.publishPercentiles(config.getPercentiles());
+        }
+
+        if (config.getBucketsMs() != null) {
+            builder.serviceLevelObjectives(Arrays.stream(config.getBucketsMs())
+                .map(Duration::ofMillis).toArray(Duration[]::new));
+        }
+
+        if (config.getMinExpectedMs() != null) {
+            
builder.minimumExpectedValue(Duration.ofMillis(config.getMinExpectedMs()));
+        }
+
+        if (config.getMaxExpectedMs() != null) {
+            
builder.maximumExpectedValue(Duration.ofMillis(config.getMaxExpectedMs()));
+        }
+
+        if (config.getDistributionStatisticExpiryMin() != null) {
+            
builder.distributionStatisticExpiry(Duration.ofMinutes(config.getDistributionStatisticExpiryMin()));
+        }
+
+        return builder.register(registry);
+    }
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DubboMetrics.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/register/MetricRegister.java
similarity index 53%
copy from 
dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DubboMetrics.java
copy to 
dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/register/MetricRegister.java
index 00351aedcc..fbf6c5eeb0 100644
--- 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DubboMetrics.java
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/register/MetricRegister.java
@@ -14,28 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.metrics;
 
-import io.micrometer.core.instrument.MeterRegistry;
-import io.micrometer.core.instrument.binder.MeterBinder;
-import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
-import org.apache.dubbo.metrics.report.AbstractMetricsReporter;
+package org.apache.dubbo.metrics.register;
 
+import io.micrometer.core.instrument.Meter;
+import org.apache.dubbo.metrics.model.sample.MetricSample;
 
-public class DubboMetrics implements MeterBinder {
+public interface MetricRegister<S extends MetricSample, M extends Meter> {
 
-    private MeterRegistry globalRegistry = null;
+    M register(S sample);
 
-    @Override
-    public void bindTo(MeterRegistry registry) {
-        globalRegistry = registry;
-        CompositeMeterRegistry compositeRegistry = 
AbstractMetricsReporter.compositeRegistry;
-        if (compositeRegistry != null) {
-            compositeRegistry.add(registry);
-        }
-    }
-
-    public void destroy() {
-    }
 }
-
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/report/AbstractMetricsReporter.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/report/AbstractMetricsReporter.java
index 4a0558b387..78215624e9 100644
--- 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/report/AbstractMetricsReporter.java
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/report/AbstractMetricsReporter.java
@@ -24,9 +24,11 @@ import org.apache.dubbo.common.constants.MetricsConstants;
 import org.apache.dubbo.common.lang.ShutdownHookCallbacks;
 import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
 import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.metrics.MetricsGlobalRegistry;
 import org.apache.dubbo.common.utils.NamedThreadFactory;
 import org.apache.dubbo.metrics.collector.AggregateMetricsCollector;
 import org.apache.dubbo.metrics.collector.MetricsCollector;
+import org.apache.dubbo.metrics.collector.HistogramMetricsCollector;
 import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
 import org.apache.dubbo.metrics.model.sample.MetricSample;
 import org.apache.dubbo.rpc.model.ApplicationModel;
@@ -68,7 +70,7 @@ public abstract class AbstractMetricsReporter implements 
MetricsReporter {
     protected final List<MetricsCollector> collectors = new ArrayList<>();
     // Avoid instances being gc due to weak references
     protected final List<MeterBinder> instanceHolder = new ArrayList<>();
-    public static final CompositeMeterRegistry compositeRegistry = new 
CompositeMeterRegistry();
+    protected final CompositeMeterRegistry compositeRegistry;
 
     private final ApplicationModel applicationModel;
 
@@ -80,6 +82,7 @@ public abstract class AbstractMetricsReporter implements 
MetricsReporter {
     protected AbstractMetricsReporter(URL url, ApplicationModel 
applicationModel) {
         this.url = url;
         this.applicationModel = applicationModel;
+        this.compositeRegistry = MetricsGlobalRegistry.getCompositeRegistry();
     }
 
     @Override
@@ -134,6 +137,7 @@ public abstract class AbstractMetricsReporter implements 
MetricsReporter {
     private void initCollectors() {
         ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
         beanFactory.getOrRegisterBean(AggregateMetricsCollector.class);
+        beanFactory.getOrRegisterBean(HistogramMetricsCollector.class);
         List<MetricsCollector> otherCollectors = 
beanFactory.getBeansOfType(MetricsCollector.class);
         collectors.addAll(otherCollectors);
     }
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DubboMetrics.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/sample/HistogramMetricSample.java
similarity index 54%
copy from 
dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DubboMetrics.java
copy to 
dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/sample/HistogramMetricSample.java
index 00351aedcc..8f8149c1b5 100644
--- 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/DubboMetrics.java
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/sample/HistogramMetricSample.java
@@ -14,28 +14,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.metrics;
 
-import io.micrometer.core.instrument.MeterRegistry;
-import io.micrometer.core.instrument.binder.MeterBinder;
-import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
-import org.apache.dubbo.metrics.report.AbstractMetricsReporter;
+package org.apache.dubbo.metrics.sample;
 
+import org.apache.dubbo.metrics.model.MetricsCategory;
+import org.apache.dubbo.metrics.model.sample.MetricSample;
 
-public class DubboMetrics implements MeterBinder {
+import java.util.Map;
 
-    private MeterRegistry globalRegistry = null;
+public class HistogramMetricSample extends MetricSample {
 
-    @Override
-    public void bindTo(MeterRegistry registry) {
-        globalRegistry = registry;
-        CompositeMeterRegistry compositeRegistry = 
AbstractMetricsReporter.compositeRegistry;
-        if (compositeRegistry != null) {
-            compositeRegistry.add(registry);
-        }
+    public HistogramMetricSample(String name, String description, Map<String, 
String> tags, MetricsCategory category) {
+        super(name, description, tags, Type.TIMER, category);
     }
 
-    public void destroy() {
+    public HistogramMetricSample(String name, String description, Map<String, 
String> tags, Type type, MetricsCategory category, String baseUnit) {
+        super(name, description, tags, type, category, baseUnit);
     }
 }
-


Reply via email to