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

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


The following commit(s) were added to refs/heads/3.3 by this push:
     new 5ae875d951 Add support for error code metrics (#12125) (#12661)
5ae875d951 is described below

commit 5ae875d951d354a2f2d3316fc08cab406a3e947e
Author: namelessssssssssss 
<[email protected]>
AuthorDate: Wed Aug 9 17:56:47 2023 +0800

    Add support for error code metrics (#12125) (#12661)
    
    * Add metrics support of error code
    
    * Add metrics support of error code
    
    * Add metrics support of error code
    
    * add license
    
    * remove hashcode override
    
    * Update DefaultSubDispatcher.java
    
    * Update ErrorCodeSampleTest.java
    
    * Update DefaultMetricsCollector.java
    
    ---------
    
    Co-authored-by: songxiaosheng <[email protected]>
---
 .../dubbo/common/constants/MetricsConstants.java   |  2 +
 .../dubbo/common/logger/ListenableLogger.java      | 23 ++++---
 .../apache/dubbo/common/logger/LogListener.java    | 18 ++----
 .../support/FailsafeErrorTypeAwareLogger.java      | 59 ++++++++++++++++-
 .../dubbo/metrics/model/ErrorCodeMetric.java       | 51 +++++++++++++++
 .../dubbo/metrics/model/MetricsCategory.java       |  1 +
 .../dubbo/metrics/model/ThreadPoolMetric.java      |  1 +
 .../metrics/model/ThreadPoolRejectMetric.java      |  2 +
 .../apache/dubbo/metrics/model/key/MetricsKey.java |  3 +
 .../metrics/collector/DefaultMetricsCollector.java | 15 ++++-
 .../sample/ErrorCodeMetricsListenRegister.java     | 41 ++++++++++++
 .../metrics/collector/sample/ErrorCodeSampler.java | 74 ++++++++++++++++++++++
 .../collector/sample/MetricsNameCountSampler.java  | 69 ++++++++++++++++++++
 .../sample/SimpleMetricsCountSampler.java          |  1 +
 .../sample/ThreadRejectMetricsCountSampler.java    | 54 ++++------------
 .../dubbo/metrics/event/DefaultSubDispatcher.java  |  1 +
 .../metrics/model/sample/ErrorCodeSampleTest.java  | 70 ++++++++++++++++++++
 17 files changed, 413 insertions(+), 72 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 e7805eaa32..49bd9665c7 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
@@ -47,6 +47,8 @@ public interface MetricsConstants {
     
     String TAG_CHANGE_TYPE = "change.type";
 
+    String TAG_ERROR_CODE = "error";
+
     String ENABLE_JVM_METRICS_KEY = "enable.jvm";
 
     String AGGREGATION_COLLECTOR_KEY = "aggregation";
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/ListenableLogger.java
similarity index 69%
copy from 
dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java
copy to 
dubbo-common/src/main/java/org/apache/dubbo/common/logger/ListenableLogger.java
index e071a7ddff..e0d3c76cae 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/ListenableLogger.java
@@ -15,19 +15,18 @@
  * limitations under the License.
  */
 
-package org.apache.dubbo.metrics.model;
+package org.apache.dubbo.common.logger;
 
 /**
- * Metric category.
+ *  Loggers that can register to listen to log messages.
  */
-public enum MetricsCategory {
-    RT,
-    QPS,
-    REQUESTS,
-    APPLICATION,
-    CONFIGCENTER,
-    REGISTRY,
-    METADATA,
-    THREAD_POOL,
-    NETTY,
+public interface ListenableLogger extends ErrorTypeAwareLogger{
+
+    /**
+     * Register a listener to this logger,and get notified when a log happens.
+     *
+     * @param listener log listener
+     */
+    void registerListen(LogListener listener);
+
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java
 b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/LogListener.java
similarity index 79%
copy from 
dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java
copy to 
dubbo-common/src/main/java/org/apache/dubbo/common/logger/LogListener.java
index e071a7ddff..c0308e8a41 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/LogListener.java
@@ -15,19 +15,13 @@
  * limitations under the License.
  */
 
-package org.apache.dubbo.metrics.model;
+package org.apache.dubbo.common.logger;
 
 /**
- * Metric category.
+ * Log Listener, can registered to an {@link ListenableLogger}.
  */
-public enum MetricsCategory {
-    RT,
-    QPS,
-    REQUESTS,
-    APPLICATION,
-    CONFIGCENTER,
-    REGISTRY,
-    METADATA,
-    THREAD_POOL,
-    NETTY,
+public interface LogListener {
+
+    void onMessage(String code, String msg);
+
 }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLogger.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLogger.java
index 8438c0ebfd..f5b7d5ef5a 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLogger.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLogger.java
@@ -18,16 +18,22 @@
 package org.apache.dubbo.common.logger.support;
 
 import org.apache.dubbo.common.Version;
-import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
+import org.apache.dubbo.common.logger.ListenableLogger;
+import org.apache.dubbo.common.logger.LogListener;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.utils.NetUtils;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.regex.Pattern;
 
 /**
  * A fail-safe (ignoring exception thrown by logger) wrapper of error type 
aware logger.
  */
-public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements 
ErrorTypeAwareLogger {
+public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements 
ListenableLogger {
 
     /**
      * Template address for formatting.
@@ -36,6 +42,16 @@ public class FailsafeErrorTypeAwareLogger extends 
FailsafeLogger implements Erro
 
     private static final Pattern ERROR_CODE_PATTERN = 
Pattern.compile("\\d+-\\d+");
 
+    /**
+     * Listeners that listened to all Loggers.
+     */
+    private static final List<LogListener> GLOBAL_LISTENERS = 
Collections.synchronizedList(new ArrayList<>());
+
+    /**
+     *  Listeners that listened to this listener.
+     */
+    private final AtomicReference<List<LogListener>> listeners = new 
AtomicReference<>();
+
     public FailsafeErrorTypeAwareLogger(Logger logger) {
         super(logger);
     }
@@ -80,6 +96,7 @@ public class FailsafeErrorTypeAwareLogger extends 
FailsafeLogger implements Erro
         }
 
         try {
+            onEvent(code, msg);
             getLogger().warn(appendContextMessageWithInstructions(code, cause, 
extendedInformation, msg));
         } catch (Throwable t) {
             // ignored.
@@ -93,6 +110,7 @@ public class FailsafeErrorTypeAwareLogger extends 
FailsafeLogger implements Erro
         }
 
         try {
+            onEvent(code, msg);
             getLogger().warn(appendContextMessageWithInstructions(code, cause, 
extendedInformation, msg), e);
         } catch (Throwable t) {
             // ignored.
@@ -106,6 +124,7 @@ public class FailsafeErrorTypeAwareLogger extends 
FailsafeLogger implements Erro
         }
 
         try {
+            onEvent(code, msg);
             getLogger().error(appendContextMessageWithInstructions(code, 
cause, extendedInformation, msg));
         } catch (Throwable t) {
             // ignored.
@@ -119,9 +138,45 @@ public class FailsafeErrorTypeAwareLogger extends 
FailsafeLogger implements Erro
         }
 
         try {
+            onEvent(code, msg);
             getLogger().error(appendContextMessageWithInstructions(code, 
cause, extendedInformation, msg), e);
         } catch (Throwable t) {
             // ignored.
         }
     }
+
+    public static void registerGlobalListen(LogListener listener) {
+        GLOBAL_LISTENERS.add(listener);
+    }
+
+    @Override
+    public void registerListen(LogListener listener) {
+        listeners.getAndUpdate(logListeners -> {
+            if (logListeners == null) {
+                logListeners = Collections.synchronizedList(new ArrayList<>());
+            }
+            logListeners.add(listener);
+            return logListeners;
+        });
+    }
+
+    private void onEvent(String code, String msg) {
+        Optional.ofNullable(listeners.get()).ifPresent(
+            logListeners -> logListeners.forEach(logListener -> {
+                try {
+                    logListener.onMessage(code, msg);
+                } catch (Exception e) {
+                    // ignored.
+                }
+            }));
+
+        GLOBAL_LISTENERS.forEach(logListener -> {
+            try {
+                logListener.onMessage(code, msg);
+            } catch (Exception e) {
+                // ignored.
+            }
+        });
+    }
+
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ErrorCodeMetric.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ErrorCodeMetric.java
new file mode 100644
index 0000000000..6553761783
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ErrorCodeMetric.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.metrics.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static 
org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;
+import static 
org.apache.dubbo.common.constants.MetricsConstants.TAG_ERROR_CODE;
+
+/**
+ * ErrorCodeMetric. Provide tags for error code metrics.
+ */
+public class ErrorCodeMetric implements Metric {
+
+    private final String errorCode;
+
+    private final String applicationName;
+
+    public ErrorCodeMetric(String applicationName, String errorCode) {
+        this.errorCode = errorCode;
+        this.applicationName = applicationName;
+    }
+
+    @Override
+    public Map<String, String> getTags() {
+        Map<String, String> tags = new HashMap<>();
+        tags.put(TAG_ERROR_CODE, errorCode);
+        tags.put(TAG_APPLICATION_NAME, applicationName);
+        return tags;
+    }
+
+    public String getErrorCode() {
+        return errorCode;
+    }
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java
index e071a7ddff..66d5d8b492 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java
@@ -29,5 +29,6 @@ public enum MetricsCategory {
     REGISTRY,
     METADATA,
     THREAD_POOL,
+    ERROR_CODE,
     NETTY,
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolMetric.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolMetric.java
index 002653359b..c45815f106 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolMetric.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolMetric.java
@@ -85,6 +85,7 @@ public class ThreadPoolMetric implements Metric{
         return Objects.hash(applicationName, threadPoolName);
     }
 
+    @Override
     public Map<String, String> getTags() {
         Map<String, String> tags = new HashMap<>();
         tags.put(TAG_IP, getLocalHost());
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolRejectMetric.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolRejectMetric.java
index 8706070847..c2daf4b5a9 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolRejectMetric.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolRejectMetric.java
@@ -30,6 +30,7 @@ import static 
org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME;
 import static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP;
 
 public class ThreadPoolRejectMetric implements Metric{
+
     private String applicationName;
 
     private String threadPoolName;
@@ -69,6 +70,7 @@ public class ThreadPoolRejectMetric implements Metric{
         return Objects.hash(applicationName, threadPoolName);
     }
 
+    @Override
     public Map<String, String> getTags() {
         Map<String, String> tags = new HashMap<>();
         tags.put(TAG_IP, getLocalHost());
diff --git 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKey.java
 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKey.java
index 5f0c003876..d426898255 100644
--- 
a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKey.java
+++ 
b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKey.java
@@ -124,6 +124,9 @@ public enum MetricsKey {
     // consumer metrics key
     INVOKER_NO_AVAILABLE_COUNT("dubbo.consumer.invoker.no.available.count", 
"Request Throw No Invoker Available Exception Count"),
 
+    // count the number of occurrences of each error code
+    ERROR_CODE_COUNT("dubbo.error.code.count","The Count Of Occurrences for 
Each Error Code"),
+
     // netty metrics key
     NETTY_ALLOCATOR_HEAP_MEMORY_USED("netty.allocator.memory.used", "Netty 
Allocator Memory Used"),
     NETTY_ALLOCATOR_DIRECT_MEMORY_USED("netty.allocator.direct.memory.used", 
"Netty Allocator Direct Memory Used"),
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/DefaultMetricsCollector.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/DefaultMetricsCollector.java
index 4581141771..39376d344f 100644
--- 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/DefaultMetricsCollector.java
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/DefaultMetricsCollector.java
@@ -20,10 +20,11 @@ package org.apache.dubbo.metrics.collector;
 import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.common.extension.Activate;
 import org.apache.dubbo.metrics.DefaultConstants;
-import org.apache.dubbo.metrics.collector.sample.MetricsCountSampleConfigurer;
+import org.apache.dubbo.metrics.collector.sample.ErrorCodeSampler;
 import org.apache.dubbo.metrics.collector.sample.MetricsSampler;
 import org.apache.dubbo.metrics.collector.sample.SimpleMetricsCountSampler;
 import org.apache.dubbo.metrics.collector.sample.ThreadPoolMetricsSampler;
+import org.apache.dubbo.metrics.collector.sample.MetricsCountSampleConfigurer;
 import org.apache.dubbo.metrics.data.BaseStatComposite;
 import org.apache.dubbo.metrics.data.MethodStatComposite;
 import org.apache.dubbo.metrics.data.RtStatComposite;
@@ -53,9 +54,15 @@ public class DefaultMetricsCollector extends 
CombMetricsCollector<RequestEvent>
     private boolean collectEnabled = false;
 
     private volatile boolean threadpoolCollectEnabled = false;
+
     private final ThreadPoolMetricsSampler threadPoolSampler = new 
ThreadPoolMetricsSampler(this);
+
+    private final ErrorCodeSampler errorCodeSampler;
+
     private String applicationName;
+
     private final ApplicationModel applicationModel;
+
     private final List<MetricsSampler> samplers = new ArrayList<>();
 
     public DefaultMetricsCollector(ApplicationModel applicationModel) {
@@ -74,8 +81,9 @@ public class DefaultMetricsCollector extends 
CombMetricsCollector<RequestEvent>
             }
         });
         super.setEventMulticaster(new DefaultSubDispatcher(this));
-        samplers.add(applicationSampler);
-        samplers.add(threadPoolSampler);
+        this.samplers.add(applicationSampler);
+        this.samplers.add(threadPoolSampler);
+        this.errorCodeSampler = new ErrorCodeSampler(this);
         this.applicationModel = applicationModel;
     }
 
@@ -99,6 +107,7 @@ public class DefaultMetricsCollector extends 
CombMetricsCollector<RequestEvent>
         this.collectEnabled = collectEnabled;
     }
 
+    @Override
     public boolean isCollectEnabled() {
         return collectEnabled;
     }
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeMetricsListenRegister.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeMetricsListenRegister.java
new file mode 100644
index 0000000000..82860dab51
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeMetricsListenRegister.java
@@ -0,0 +1,41 @@
+/*
+ * 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.sample;
+
+import org.apache.dubbo.common.logger.LogListener;
+import org.apache.dubbo.common.logger.support.FailsafeErrorTypeAwareLogger;
+import org.apache.dubbo.metrics.model.key.MetricsKey;
+
+/**
+ * Listen the log of all {@link FailsafeErrorTypeAwareLogger} instances, and 
add error code count to {@link ErrorCodeSampler}.
+ */
+public class ErrorCodeMetricsListenRegister implements LogListener {
+
+    private final ErrorCodeSampler errorCodeSampler;
+
+    public ErrorCodeMetricsListenRegister(ErrorCodeSampler errorCodeSampler){
+        FailsafeErrorTypeAwareLogger.registerGlobalListen(this);
+        this.errorCodeSampler = errorCodeSampler;
+        
this.errorCodeSampler.addMetricName(MetricsKey.ERROR_CODE_COUNT.getName());
+    }
+
+    @Override
+    public void onMessage(String code, String msg) {
+        errorCodeSampler.inc(code, MetricsKey.ERROR_CODE_COUNT.getName());
+    }
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeSampler.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeSampler.java
new file mode 100644
index 0000000000..86fdf79237
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeSampler.java
@@ -0,0 +1,74 @@
+/*
+ * 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.sample;
+
+import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
+import org.apache.dubbo.metrics.model.ErrorCodeMetric;
+import org.apache.dubbo.metrics.model.MetricsCategory;
+import org.apache.dubbo.metrics.model.key.MetricsKey;
+import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
+import org.apache.dubbo.metrics.model.sample.MetricSample;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * This sampler is used to count the number of occurrences of each error code.
+ */
+public class ErrorCodeSampler extends MetricsNameCountSampler<String, String, 
ErrorCodeMetric> {
+
+    private final ErrorCodeMetricsListenRegister register;
+
+    /**
+     * Map<ErrorCode,Metric>
+     */
+    private final Map<String, ErrorCodeMetric> errorCodeMetrics;
+
+    public ErrorCodeSampler(DefaultMetricsCollector collector) {
+        super(collector, MetricsCategory.ERROR_CODE, 
MetricsKey.ERROR_CODE_COUNT);
+        this.register = new ErrorCodeMetricsListenRegister(this);
+        this.errorCodeMetrics = new ConcurrentHashMap<>();
+    }
+
+    @Override
+    protected MetricSample provideMetricsSample(ErrorCodeMetric metric, 
AtomicLong count, MetricsKey metricsKey, MetricsCategory metricsCategory) {
+        return new CounterMetricSample<>(
+            metricsKey.getNameByType(metric.getErrorCode()),
+            metricsKey.getDescription(),
+            metric.getTags(),
+            metricsCategory,
+            count
+        );
+    }
+
+    @Override
+    protected void countConfigure(MetricsCountSampleConfigurer<String, String, 
ErrorCodeMetric> sampleConfigure) {
+        sampleConfigure.configureMetrics(configure -> {
+
+            String errorCode = configure.getSource();
+            ErrorCodeMetric metric = errorCodeMetrics.get(errorCode);
+
+            if (metric == null) {
+                metric = new 
ErrorCodeMetric(collector.getApplicationModel().getApplicationName(), 
errorCode);
+                errorCodeMetrics.put(errorCode, metric);
+            }
+            return metric;
+        });
+    }
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/MetricsNameCountSampler.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/MetricsNameCountSampler.java
new file mode 100644
index 0000000000..ebf7e437ce
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/MetricsNameCountSampler.java
@@ -0,0 +1,69 @@
+/*
+ * 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.sample;
+
+import org.apache.dubbo.common.utils.ConcurrentHashSet;
+import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
+import org.apache.dubbo.metrics.model.Metric;
+import org.apache.dubbo.metrics.model.MetricsCategory;
+import org.apache.dubbo.metrics.model.key.MetricsKey;
+import org.apache.dubbo.metrics.model.sample.MetricSample;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+public abstract class MetricsNameCountSampler<S, K, M extends Metric> extends 
SimpleMetricsCountSampler<S, K, M> {
+
+    protected final DefaultMetricsCollector collector;
+
+    protected final Set<K> metricNames = new ConcurrentHashSet<>();
+
+    protected final MetricsCategory metricsCategory;
+
+    protected final MetricsKey metricsKey;
+
+    public MetricsNameCountSampler(DefaultMetricsCollector 
collector,MetricsCategory metricsCategory,MetricsKey metricsKey) {
+        this.metricsCategory = metricsCategory;
+        this.metricsKey = metricsKey;
+        this.collector = collector;
+        this.collector.addSampler(this);
+    }
+
+    public void addMetricName(K name) {
+        this.metricNames.add(name);
+    }
+
+    @Override
+    public List<MetricSample> sample() {
+        List<MetricSample> metricSamples = new ArrayList<>();
+        metricNames.forEach(name -> collect(metricSamples, name));
+        return metricSamples;
+    }
+
+    private void collect(List<MetricSample> samples, K metricName) {
+        getCount(metricName)
+            .filter(e -> !e.isEmpty())
+            .ifPresent(map -> map.forEach((k, v) ->
+                
samples.add(provideMetricsSample(k,v,metricsKey,metricsCategory))));
+    }
+
+    protected abstract MetricSample provideMetricsSample(M metric,AtomicLong 
count,MetricsKey metricsKey,MetricsCategory metricsCategory);
+
+}
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/SimpleMetricsCountSampler.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/SimpleMetricsCountSampler.java
index 9c31973740..666af13f30 100644
--- 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/SimpleMetricsCountSampler.java
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/SimpleMetricsCountSampler.java
@@ -36,6 +36,7 @@ public abstract class SimpleMetricsCountSampler<S, K, M 
extends Metric>
     implements MetricsCountSampler<S, K, M> {
 
     private final ConcurrentMap<M, AtomicLong> EMPTY_COUNT = new 
ConcurrentHashMap<>();
+
     private final Map<K, ConcurrentMap<M, AtomicLong>> metricCounter = new 
ConcurrentHashMap<>();
 
     @Override
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ThreadRejectMetricsCountSampler.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ThreadRejectMetricsCountSampler.java
index e9e55f9448..2638777574 100644
--- 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ThreadRejectMetricsCountSampler.java
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ThreadRejectMetricsCountSampler.java
@@ -16,65 +16,33 @@
  */
 
 package org.apache.dubbo.metrics.collector.sample;
-import org.apache.dubbo.common.utils.ConcurrentHashSet;
+
 import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
-import org.apache.dubbo.metrics.model.Metric;
 import org.apache.dubbo.metrics.model.MetricsCategory;
-import org.apache.dubbo.metrics.model.key.MetricsKey;
 import org.apache.dubbo.metrics.model.ThreadPoolRejectMetric;
+import org.apache.dubbo.metrics.model.key.MetricsKey;
 import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
 import org.apache.dubbo.metrics.model.sample.MetricSample;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
+
 import java.util.concurrent.atomic.AtomicLong;
-import java.util.function.ToDoubleFunction;
-import static org.apache.dubbo.metrics.model.MetricsCategory.THREAD_POOL;
 
-public class ThreadRejectMetricsCountSampler extends 
SimpleMetricsCountSampler<String, String, ThreadPoolRejectMetric> {
+import static org.apache.dubbo.metrics.model.MetricsCategory.THREAD_POOL;
 
-    private final DefaultMetricsCollector collector;
+public class ThreadRejectMetricsCountSampler extends 
MetricsNameCountSampler<String, String, ThreadPoolRejectMetric> {
 
-    private final Set<String> metricNames = new ConcurrentHashSet<>();
     public ThreadRejectMetricsCountSampler(DefaultMetricsCollector collector) {
-        this.collector = collector;
-        this.collector.addSampler(this);
-    }
-
-    public void addMetricName(String name){
-        this.metricNames.add(name);
+        super(collector, 
THREAD_POOL,MetricsKey.THREAD_POOL_THREAD_REJECT_COUNT);
     }
 
     @Override
-    public List<MetricSample> sample() {
-        List<MetricSample> metricSamples = new ArrayList<>();
-        metricNames.stream().forEach(name->collect(metricSamples,name));
-        return metricSamples;
-    }
-
-
-    private void collect(List<MetricSample> list, String metricName) {
-        count(list, metricName, MetricsKey.THREAD_POOL_THREAD_REJECT_COUNT);
-    }
-
-    private <T extends Metric> void count(List<MetricSample> list, String 
metricName, MetricsKey metricsKey) {
-        getCount(metricName).filter(e -> !e.isEmpty())
-            .ifPresent(map -> map.forEach((k, v) ->
-                list.add(getGaugeMetricSample(metricsKey, k, THREAD_POOL, v, 
AtomicLong::get))));
-    }
-
-    private <T> GaugeMetricSample<T> getGaugeMetricSample(MetricsKey 
metricsKey,
-                                                          
ThreadPoolRejectMetric methodMetric,
-                                                          MetricsCategory 
metricsCategory,
-                                                          T value,
-                                                          ToDoubleFunction<T> 
apply) {
+    protected MetricSample provideMetricsSample(ThreadPoolRejectMetric metric, 
AtomicLong count, MetricsKey metricsKey, MetricsCategory metricsCategory) {
         return new GaugeMetricSample<>(
-            metricsKey.getNameByType(methodMetric.getThreadPoolName()),
+            metricsKey.getNameByType(metric.getThreadPoolName()),
             metricsKey.getDescription(),
-            methodMetric.getTags(),
+            metric.getTags(),
             metricsCategory,
-            value,
-            apply);
+            count,
+            AtomicLong::get);
     }
 
     @Override
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/DefaultSubDispatcher.java
 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/DefaultSubDispatcher.java
index 807736709b..d9a88c466d 100644
--- 
a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/DefaultSubDispatcher.java
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/DefaultSubDispatcher.java
@@ -96,6 +96,7 @@ public final class DefaultSubDispatcher extends 
SimpleMetricsEventMulticaster {
                             MetricsSupport.incrAndAddRt(targetKey, 
dynamicPlaceType, (MethodMetricsCollector) collector, event);
                         }
                 )));
+
     }
 
 }
diff --git 
a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/sample/ErrorCodeSampleTest.java
 
b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/sample/ErrorCodeSampleTest.java
new file mode 100644
index 0000000000..89b2ca5fa3
--- /dev/null
+++ 
b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/sample/ErrorCodeSampleTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.metrics.model.sample;
+
+import org.apache.dubbo.common.utils.Assert;
+import org.apache.dubbo.common.utils.ReflectionUtils;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
+import 
org.apache.dubbo.metrics.collector.sample.ErrorCodeMetricsListenRegister;
+import org.apache.dubbo.metrics.collector.sample.ErrorCodeSampler;
+import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
+import org.apache.dubbo.metrics.model.sample.MetricSample;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class ErrorCodeSampleTest {
+
+    @Test
+    void testErrorCodeMetric() {
+        FrameworkModel frameworkModel = FrameworkModel.defaultModel();
+        ApplicationModel applicationModel = frameworkModel.newApplication();
+
+        ApplicationConfig applicationConfig = new ApplicationConfig();
+        applicationConfig.setName("MyApplication1");
+
+        
applicationModel.getApplicationConfigManager().setApplication(applicationConfig);
+
+        DefaultMetricsCollector defaultMetricsCollector = new 
DefaultMetricsCollector(applicationModel);
+        defaultMetricsCollector.setCollectEnabled(true);
+
+        ErrorCodeSampler sampler = (ErrorCodeSampler) 
ReflectionUtils.getField(defaultMetricsCollector, "errorCodeSampler");
+
+        ErrorCodeMetricsListenRegister register = 
(ErrorCodeMetricsListenRegister) ReflectionUtils.getField(sampler, "register");
+
+        register.onMessage("0-1", null);
+        register.onMessage("0-1", null);
+        register.onMessage("0-2", null);
+        register.onMessage("0-2", null);
+        register.onMessage("1-2", null);
+        register.onMessage("1-2", null);
+        register.onMessage("1-3", null);
+        register.onMessage("1-3", null);
+
+        List<MetricSample> samples = defaultMetricsCollector.collect();
+
+        Assert.assertTrue(samples.size() == 4,"Wrong number of samples.");
+        samples.forEach(metricSample ->  
Assert.assertTrue(((AtomicLong)((CounterMetricSample<?>)metricSample).getValue()).get()
 == 2L,"Sample count error."));
+
+        System.out.println(samples);
+    }
+}


Reply via email to