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 a8fd9a91ef..74a4fe4221 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 @@ -20,9 +20,57 @@ public interface MetricsConstants { String PROTOCOL_PROMETHEUS = "prometheus"; - String AGGREGATION_ENABLE = "aggregation.enable"; + String TAG_IP = "ip"; - String AGGREGATION_BUCKET_NUM = "aggregation.bucket.num"; + String TAG_HOSTNAME = "hostname"; - String AGGREGATION_TIME_WINDOW_SECONDS = "aggregation.time.window.seconds"; + String TAG_APPLICATION_NAME = "application.name"; + + String TAG_INTERFACE_KEY = "interface"; + + String TAG_METHOD_KEY = "method"; + + String TAG_GROUP_KEY = "group"; + + String TAG_VERSION_KEY = "version"; + + String ENABLE_JVM_METRICS_KEY = "enable.jvm.metrics"; + + String AGGREGATION_COLLECTOR_KEY = "aggregation"; + + String AGGREGATION_ENABLED_KEY = "aggregation.enabled"; + + String AGGREGATION_BUCKET_NUM_KEY = "aggregation.bucket.num"; + + String AGGREGATION_TIME_WINDOW_SECONDS_KEY = "aggregation.time.window.seconds"; + + String PROMETHEUS_EXPORTER_ENABLED_KEY = "prometheus.exporter.enabled"; + + String PROMETHEUS_EXPORTER_ENABLE_HTTP_SERVICE_DISCOVERY_KEY = "prometheus.exporter.enable.http.service.discovery"; + + String PROMETHEUS_EXPORTER_HTTP_SERVICE_DISCOVERY_URL_KEY = "prometheus.exporter.http.service.discovery.url"; + + String PROMETHEUS_EXPORTER_METRICS_PORT_KEY = "prometheus.exporter.metrics.port"; + + String PROMETHEUS_EXPORTER_METRICS_PATH_KEY = "prometheus.exporter.metrics.path"; + + String PROMETHEUS_PUSHGATEWAY_ENABLED_KEY = "prometheus.pushgateway.enabled"; + + String PROMETHEUS_PUSHGATEWAY_BASE_URL_KEY = "prometheus.pushgateway.base.url"; + + String PROMETHEUS_PUSHGATEWAY_USERNAME_KEY = "prometheus.pushgateway.username"; + + String PROMETHEUS_PUSHGATEWAY_PASSWORD_KEY = "prometheus.pushgateway.password"; + + String PROMETHEUS_PUSHGATEWAY_PUSH_INTERVAL_KEY = "prometheus.pushgateway.push.interval"; + + String PROMETHEUS_PUSHGATEWAY_JOB_KEY = "prometheus.pushgateway.job"; + + int PROMETHEUS_DEFAULT_METRICS_PORT = 20888; + + String PROMETHEUS_DEFAULT_METRICS_PATH = "/metrics"; + + int PROMETHEUS_DEFAULT_PUSH_INTERVAL = 30; + + String PROMETHEUS_DEFAULT_JOB_NAME = "default_dubbo_job"; } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/MetricsReporter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/MetricsReporter.java new file mode 100644 index 0000000000..b07af77888 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/MetricsReporter.java @@ -0,0 +1,30 @@ +/* + * 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.common.metrics; + +/** + * Metrics Reporter. + * Report metrics to specific metrics server(e.g. Prometheus). + */ +public interface MetricsReporter { + + /** + * Initialize metrics reporter. + */ + void init(); +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/MetricsReporterFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/MetricsReporterFactory.java new file mode 100644 index 0000000000..ade70ca3c8 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/MetricsReporterFactory.java @@ -0,0 +1,39 @@ +/* + * 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.common.metrics; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.extension.Adaptive; +import org.apache.dubbo.common.extension.ExtensionScope; +import org.apache.dubbo.common.extension.SPI; + +/** + * The factory interface to create the instance of {@link MetricsReporter}. + */ +@SPI(value = "nop", scope = ExtensionScope.APPLICATION) +public interface MetricsReporterFactory { + + /** + * Create metrics reporter. + * + * @param url URL + * @return Metrics reporter implementation. + */ + @Adaptive({"protocol"}) + MetricsReporter createMetricsReporter(URL url); +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/collector/DefaultMetricsCollector.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/collector/DefaultMetricsCollector.java new file mode 100644 index 0000000000..599b6c83b9 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/collector/DefaultMetricsCollector.java @@ -0,0 +1,187 @@ +/* + * 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.common.metrics.collector; + +import org.apache.dubbo.common.metrics.event.MetricsEvent; +import org.apache.dubbo.common.metrics.event.RTEvent; +import org.apache.dubbo.common.metrics.event.RequestEvent; +import org.apache.dubbo.common.metrics.listener.MetricsListener; +import org.apache.dubbo.common.metrics.model.MethodMetric; +import org.apache.dubbo.common.metrics.model.MetricsKey; +import org.apache.dubbo.common.metrics.model.sample.GaugeMetricSample; +import org.apache.dubbo.common.metrics.model.sample.MetricSample; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.LongAccumulator; + +import static org.apache.dubbo.common.metrics.model.MetricsCategory.REQUESTS; +import static org.apache.dubbo.common.metrics.model.MetricsCategory.RT; + +/** + * Default implementation of {@link MetricsCollector} + */ +public class DefaultMetricsCollector implements MetricsCollector { + + private AtomicBoolean collectEnabled = new AtomicBoolean(false); + private final List listeners = new ArrayList<>(); + private final ApplicationModel applicationModel; + private final String applicationName; + + private final Map totalRequests = new ConcurrentHashMap<>(); + private final Map succeedRequests = new ConcurrentHashMap<>(); + private final Map failedRequests = new ConcurrentHashMap<>(); + private final Map processingRequests = new ConcurrentHashMap<>(); + + private final Map lastRT = new ConcurrentHashMap<>(); + private final Map minRT = new ConcurrentHashMap<>(); + private final Map maxRT = new ConcurrentHashMap<>(); + private final Map avgRT = new ConcurrentHashMap<>(); + private final Map totalRT = new ConcurrentHashMap<>(); + private final Map rtCount = new ConcurrentHashMap<>(); + + public DefaultMetricsCollector(ApplicationModel applicationModel) { + this.applicationModel = applicationModel; + this.applicationName = applicationModel.getApplicationName(); + } + + public void setCollectEnabled(Boolean collectEnabled) { + this.collectEnabled.compareAndSet(isCollectEnabled(), collectEnabled); + } + + public Boolean isCollectEnabled() { + return collectEnabled.get(); + } + + public void addListener(MetricsListener listener) { + listeners.add(listener); + } + + public void increaseTotalRequests(String interfaceName, String methodName, String group, String version) { + if (isCollectEnabled()) { + MethodMetric metric = new MethodMetric(applicationName, interfaceName, methodName, group, version); + AtomicLong count = totalRequests.computeIfAbsent(metric, k -> new AtomicLong(0L)); + count.incrementAndGet(); + + publishEvent(new RequestEvent(metric, RequestEvent.Type.TOTAL)); + } + } + + public void increaseSucceedRequests(String interfaceName, String methodName, String group, String version) { + if (isCollectEnabled()) { + MethodMetric metric = new MethodMetric(applicationName, interfaceName, methodName, group, version); + AtomicLong count = succeedRequests.computeIfAbsent(metric, k -> new AtomicLong(0L)); + count.incrementAndGet(); + + publishEvent(new RequestEvent(metric, RequestEvent.Type.SUCCEED)); + } + } + + public void increaseFailedRequests(String interfaceName, String methodName, String group, String version) { + if (isCollectEnabled()) { + MethodMetric metric = new MethodMetric(applicationName, interfaceName, methodName, group, version); + AtomicLong count = failedRequests.computeIfAbsent(metric, k -> new AtomicLong(0L)); + count.incrementAndGet(); + + publishEvent(new RequestEvent(metric, RequestEvent.Type.FAILED)); + } + } + + public void increaseProcessingRequests(String interfaceName, String methodName, String group, String version) { + if (isCollectEnabled()) { + MethodMetric metric = new MethodMetric(applicationName, interfaceName, methodName, group, version); + AtomicLong count = processingRequests.computeIfAbsent(metric, k -> new AtomicLong(0L)); + count.incrementAndGet(); + } + } + + public void decreaseProcessingRequests(String interfaceName, String methodName, String group, String version) { + if (isCollectEnabled()) { + MethodMetric metric = new MethodMetric(applicationName, interfaceName, methodName, group, version); + AtomicLong count = processingRequests.computeIfAbsent(metric, k -> new AtomicLong(0L)); + count.decrementAndGet(); + } + } + + public void addRT(String interfaceName, String methodName, String group, String version, Long responseTime) { + if (isCollectEnabled()) { + MethodMetric metric = new MethodMetric(applicationName, interfaceName, methodName, group, version); + + AtomicLong last = lastRT.computeIfAbsent(metric, k -> new AtomicLong()); + last.set(responseTime); + + LongAccumulator min = minRT.computeIfAbsent(metric, k -> new LongAccumulator(Long::min, Long.MAX_VALUE)); + min.accumulate(responseTime); + + LongAccumulator max = maxRT.computeIfAbsent(metric, k -> new LongAccumulator(Long::max, Long.MIN_VALUE)); + max.accumulate(responseTime); + + AtomicLong total = totalRT.computeIfAbsent(metric, k -> new AtomicLong()); + total.addAndGet(responseTime); + + AtomicLong count = rtCount.computeIfAbsent(metric, k -> new AtomicLong()); + count.incrementAndGet(); + + avgRT.computeIfAbsent(metric, k -> new AtomicLong()); + + publishEvent(new RTEvent(metric, responseTime)); + } + } + + private void publishEvent(MetricsEvent event) { + for (MetricsListener listener : listeners) { + listener.onEvent(event); + } + } + + @Override + public List collect() { + List list = new ArrayList<>(); + collectRequests(list); + collectRT(list); + + return list; + } + + private void collectRequests(List list) { + totalRequests.forEach((k, v) -> list.add(new GaugeMetricSample(MetricsKey.METRIC_REQUESTS_TOTAL, k.getTags(), REQUESTS, v::get))); + succeedRequests.forEach((k, v) -> list.add(new GaugeMetricSample(MetricsKey.METRIC_REQUESTS_SUCCEED, k.getTags(), REQUESTS, v::get))); + failedRequests.forEach((k, v) -> list.add(new GaugeMetricSample(MetricsKey.METRIC_REQUESTS_FAILED, k.getTags(), REQUESTS, v::get))); + processingRequests.forEach((k, v) -> list.add(new GaugeMetricSample(MetricsKey.METRIC_REQUESTS_PROCESSING, k.getTags(), REQUESTS, v::get))); + } + + private void collectRT(List list) { + lastRT.forEach((k, v) -> list.add(new GaugeMetricSample(MetricsKey.METRIC_RT_LAST, k.getTags(), RT, v::get))); + minRT.forEach((k, v) -> list.add(new GaugeMetricSample(MetricsKey.METRIC_RT_MIN, k.getTags(), RT, v::get))); + maxRT.forEach((k, v) -> list.add(new GaugeMetricSample(MetricsKey.METRIC_RT_MAX, k.getTags(), RT, v::get))); + + totalRT.forEach((k, v) -> { + list.add(new GaugeMetricSample(MetricsKey.METRIC_RT_TOTAL, k.getTags(), RT, v::get)); + + AtomicLong avg = avgRT.get(k); + AtomicLong count = rtCount.get(k); + avg.set(v.get() / count.get()); + list.add(new GaugeMetricSample(MetricsKey.METRIC_RT_AVG, k.getTags(), RT, avg::get)); + }); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/collector/MetricsCollector.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/collector/MetricsCollector.java new file mode 100644 index 0000000000..12eaa2a979 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/collector/MetricsCollector.java @@ -0,0 +1,36 @@ +/* + * 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.common.metrics.collector; + +import org.apache.dubbo.common.metrics.model.sample.MetricSample; + +import java.util.List; + +/** + * Metrics Collector. + * An interface of collector to collect framework internal metrics. + */ +public interface MetricsCollector { + + /** + * Collect metrics as {@link MetricSample} + * + * @return List of MetricSample + */ + List collect(); +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/event/MetricsEvent.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/event/MetricsEvent.java new file mode 100644 index 0000000000..3b009db980 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/event/MetricsEvent.java @@ -0,0 +1,45 @@ +/* + * 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.common.metrics.event; + +/** + * BaseMetricsEvent. + */ +public abstract class MetricsEvent { + + /** + * Metric object. (eg. {@link org.apache.dubbo.common.metrics.model.MethodMetric}) + */ + protected transient Object source; + + public MetricsEvent(Object source) { + if (source == null) { + throw new IllegalArgumentException("null source"); + } + + this.source = source; + } + + public Object getSource() { + return source; + } + + public String toString() { + return getClass().getName() + "[source=" + source + "]"; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/event/RTEvent.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/event/RTEvent.java new file mode 100644 index 0000000000..68887dcb99 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/event/RTEvent.java @@ -0,0 +1,38 @@ +/* + * 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.common.metrics.event; + +/** + * RtEvent. + */ +public class RTEvent extends MetricsEvent { + private Long rt; + + public RTEvent(Object source, Long rt) { + super(source); + this.rt = rt; + } + + public Long getRt() { + return rt; + } + + public void setRt(Long rt) { + this.rt = rt; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/event/RequestEvent.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/event/RequestEvent.java new file mode 100644 index 0000000000..b1d050bcb9 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/event/RequestEvent.java @@ -0,0 +1,45 @@ +/* + * 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.common.metrics.event; + +/** + * RequestEvent. + */ +public class RequestEvent extends MetricsEvent { + private Type type; + + public RequestEvent(Object source, Type type) { + super(source); + this.type = type; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public enum Type { + TOTAL, + SUCCEED, + FAILED, + PROCESSING + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/listener/MetricsListener.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/listener/MetricsListener.java new file mode 100644 index 0000000000..0f55e9b42c --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/listener/MetricsListener.java @@ -0,0 +1,33 @@ +/* + * 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.common.metrics.listener; + +import org.apache.dubbo.common.metrics.event.MetricsEvent; + +/** + * Metrics Listener. + */ +public interface MetricsListener { + + /** + * notify event. + * + * @param event BaseMetricsEvent + */ + void onEvent(MetricsEvent event); +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/MethodMetric.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/MethodMetric.java new file mode 100644 index 0000000000..3e3f75a601 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/MethodMetric.java @@ -0,0 +1,124 @@ +/* + * 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.common.metrics.model; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY; +import static org.apache.dubbo.common.utils.NetUtils.getLocalHost; +import static org.apache.dubbo.common.utils.NetUtils.getLocalHostName; + +/** + * Metric class for method. + */ +public class MethodMetric { + private String applicationName; + private String interfaceName; + private String methodName; + private String group; + private String version; + + public MethodMetric() { + + } + + public MethodMetric(String applicationName, String interfaceName, String methodName, String group, String version) { + this.applicationName = applicationName; + this.interfaceName = interfaceName; + this.methodName = methodName; + this.group = group; + this.version = version; + } + + public String getInterfaceName() { + return interfaceName; + } + + public void setInterfaceName(String interfaceName) { + this.interfaceName = interfaceName; + } + + public String getMethodName() { + return methodName; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public Map getTags() { + Map tags = new HashMap<>(); + tags.put(TAG_IP, getLocalHost()); + tags.put(TAG_HOSTNAME, getLocalHostName()); + tags.put(TAG_APPLICATION_NAME, applicationName); + + tags.put(TAG_INTERFACE_KEY, interfaceName); + tags.put(TAG_METHOD_KEY, methodName); + tags.put(TAG_GROUP_KEY, group); + tags.put(TAG_VERSION_KEY, version); + return tags; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MethodMetric that = (MethodMetric) o; + return Objects.equals(interfaceName, that.interfaceName) && Objects.equals(methodName, that.methodName) + && Objects.equals(group, that.group) && Objects.equals(version, that.version); + } + + @Override + public int hashCode() { + return Objects.hash(interfaceName, methodName, group, version); + } + + @Override + public String toString() { + return "MethodMetric{" + + "interfaceName='" + interfaceName + '\'' + + ", methodName='" + methodName + '\'' + + ", group='" + group + '\'' + + ", version='" + version + '\'' + + '}'; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/MetricsCategory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/MetricsCategory.java new file mode 100644 index 0000000000..700a47f21f --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/MetricsCategory.java @@ -0,0 +1,27 @@ +/* + * 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.common.metrics.model; + +/** + * Metric category. + */ +public enum MetricsCategory { + RT, + QPS, + REQUESTS, +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/MetricsKey.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/MetricsKey.java new file mode 100644 index 0000000000..3c9ff0221f --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/MetricsKey.java @@ -0,0 +1,54 @@ +/* + * 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.common.metrics.model; + +public enum MetricsKey { + + METRIC_REQUESTS_TOTAL("requests.total", "Total Requests"), + METRIC_REQUESTS_SUCCEED("requests.succeed", "Succeed Requests"), + METRIC_REQUESTS_FAILED("requests.failed", "Failed Requests"), + METRIC_REQUESTS_PROCESSING("requests.processing", "Processing Requests"), + METRIC_REQUESTS_TOTAL_AGG("requests.total.aggregate", "Aggregated Total Requests"), + METRIC_REQUESTS_SUCCEED_AGG("requests.succeed.aggregate", "Aggregated Succeed Requests"), + METRIC_REQUESTS_FAILED_AGG("requests.failed.aggregate", "Aggregated Failed Requests"), + METRIC_QPS_NAME("qps", "Query Per Seconds"), + METRIC_RT_LAST("rt.last", "Last Response Time"), + METRIC_RT_MIN("rt.min", "Min Response Time"), + METRIC_RT_MAX("rt.max", "Max Response Time"), + METRIC_RT_TOTAL("rt.total", "Total Response Time"), + METRIC_RT_AVG("rt.avg", "Average Response Time"), + METRIC_RT_P99("rt.p99", "Response Time P99"), + METRIC_RT_P95("rt.p95", "Response Time P95"), + ; + + private final String name; + private final String description; + + public final String getName() { + return this.name; + } + + public final String getDescription() { + return this.description; + } + + MetricsKey(String name, String description) { + this.name = name; + this.description = description; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/sample/GaugeMetricSample.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/sample/GaugeMetricSample.java new file mode 100644 index 0000000000..1bdb2aaada --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/sample/GaugeMetricSample.java @@ -0,0 +1,50 @@ +/* + * 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.common.metrics.model.sample; + +import org.apache.dubbo.common.metrics.model.MetricsCategory; +import org.apache.dubbo.common.metrics.model.MetricsKey; + +import java.util.Map; +import java.util.function.Supplier; + +/** + * GaugeMetricSample. + */ +public class GaugeMetricSample extends MetricSample { + + private Supplier supplier; + + public GaugeMetricSample(MetricsKey metricsKey, Map tags, MetricsCategory category, Supplier supplier) { + super(metricsKey.getName(), metricsKey.getDescription(), tags, Type.GAUGE, category); + this.supplier = supplier; + } + + public GaugeMetricSample(String name, String description, Map tags, MetricsCategory category, String baseUnit, Supplier supplier) { + super(name, description, tags, Type.GAUGE, category, baseUnit); + this.supplier = supplier; + } + + public Supplier getSupplier() { + return supplier; + } + + public void setSupplier(Supplier supplier) { + this.supplier = supplier; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/sample/MetricSample.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/sample/MetricSample.java new file mode 100644 index 0000000000..21fe5e0446 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/model/sample/MetricSample.java @@ -0,0 +1,131 @@ +/* + * 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.common.metrics.model.sample; + +import org.apache.dubbo.common.metrics.model.MetricsCategory; + +import java.util.Map; +import java.util.Objects; + +/** + * MetricSample. + */ +public class MetricSample { + private String name; + private String description; + private Map tags; + private Type type; + private MetricsCategory category; + private String baseUnit; + + public MetricSample(String name, String description, Map tags, Type type, MetricsCategory category) { + this(name, description, tags, type, category, null); + } + + public MetricSample(String name, String description, Map tags, Type type, MetricsCategory category, String baseUnit) { + this.name = name; + this.description = description; + this.tags = tags; + this.type = type; + this.category = category; + this.baseUnit = baseUnit; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Map getTags() { + return tags; + } + + public void setTags(Map tags) { + this.tags = tags; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public MetricsCategory getCategory() { + return category; + } + + public void setCategory(MetricsCategory category) { + this.category = category; + } + + public String getBaseUnit() { + return baseUnit; + } + + public void setBaseUnit(String baseUnit) { + this.baseUnit = baseUnit; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MetricSample that = (MetricSample) o; + return Objects.equals(name, that.name) && Objects.equals(description, that.description) + && Objects.equals(baseUnit, that.baseUnit) && type == that.type + && Objects.equals(category, that.category) && Objects.equals(tags, that.tags); + } + + @Override + public int hashCode() { + return Objects.hash(name, description, baseUnit, type, category, tags); + } + + @Override + public String toString() { + return "MetricSample{" + + "name='" + name + '\'' + + ", description='" + description + '\'' + + ", baseUnit='" + baseUnit + '\'' + + ", type=" + type + + ", category=" + category + + ", tags=" + tags + + '}'; + } + + public enum Type { + COUNTER, + GAUGE, + LONG_TASK_TIMER, + TIMER, + DISTRIBUTION_SUMMARY + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/nop/NopMetricsReporter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/nop/NopMetricsReporter.java new file mode 100644 index 0000000000..07e8c6c96c --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/nop/NopMetricsReporter.java @@ -0,0 +1,36 @@ +/* + * 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.common.metrics.nop; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.metrics.MetricsReporter; + +/** + * Metrics reporter without any operations. + */ +public class NopMetricsReporter implements MetricsReporter { + + public NopMetricsReporter(URL url) { + + } + + @Override + public void init() { + + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/nop/NopMetricsReporterFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/nop/NopMetricsReporterFactory.java new file mode 100644 index 0000000000..462de5e49d --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/nop/NopMetricsReporterFactory.java @@ -0,0 +1,33 @@ +/* + * 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.common.metrics.nop; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.metrics.MetricsReporter; +import org.apache.dubbo.common.metrics.MetricsReporterFactory; + +/** + * MetricsReporterFactory to create NopMetricsReporter. + */ +public class NopMetricsReporterFactory implements MetricsReporterFactory { + + @Override + public MetricsReporter createMetricsReporter(URL url) { + return new NopMetricsReporter(url); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/service/MetricsEntity.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/service/MetricsEntity.java new file mode 100644 index 0000000000..7c64e290e3 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/service/MetricsEntity.java @@ -0,0 +1,91 @@ +/* + * 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.common.metrics.service; + +import org.apache.dubbo.common.metrics.model.MetricsCategory; + +import java.util.Map; +import java.util.Objects; + +/** + * Metrics response entity. + */ +public class MetricsEntity { + + private String name; + private Map tags; + private MetricsCategory category; + private Object value; + + public MetricsEntity() { + + } + + public MetricsEntity(String name, Map tags, MetricsCategory category, Object value) { + this.name = name; + this.tags = tags; + this.category = category; + this.value = value; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getTags() { + return tags; + } + + public void setTags(Map tags) { + this.tags = tags; + } + + public MetricsCategory getCategory() { + return category; + } + + public void setCategory(MetricsCategory category) { + this.category = category; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MetricsEntity entity = (MetricsEntity) o; + return Objects.equals(name, entity.name) && Objects.equals(tags, entity.tags) + && Objects.equals(category, entity.category) && Objects.equals(value, entity.value); + } + + @Override + public int hashCode() { + return Objects.hash(name, tags, category, value); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/service/MetricsService.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/service/MetricsService.java new file mode 100644 index 0000000000..7c8724e8da --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/service/MetricsService.java @@ -0,0 +1,73 @@ +/* + * 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.common.metrics.service; + +import org.apache.dubbo.common.extension.ExtensionScope; +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.common.metrics.model.MetricsCategory; + +import java.util.List; +import java.util.Map; + +import static org.apache.dubbo.common.metrics.service.MetricsService.DEFAULT_EXTENSION_NAME; + +/** + * Metrics Service. + * Provide an interface to get metrics from {@link org.apache.dubbo.common.metrics.collector.MetricsCollector} + */ +@SPI(value = DEFAULT_EXTENSION_NAME, scope = ExtensionScope.APPLICATION) +public interface MetricsService { + + /** + * Default {@link MetricsService} extension name. + */ + String DEFAULT_EXTENSION_NAME = "default"; + + /** + * The contract version of {@link MetricsService}, the future update must make sure compatible. + */ + String VERSION = "1.0.0"; + + /** + * Get metrics by prefixes + * + * @param categories categories + * @return metrics - key=MetricCategory value=MetricsEntityList + */ + Map> getMetricsByCategories(List categories); + + /** + * Get metrics by interface and prefixes + * + * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) + * @param categories categories + * @return metrics - key=MetricCategory value=MetricsEntityList + */ + Map> getMetricsByCategories(String serviceUniqueName, List categories); + + /** + * Get metrics by interface态method and prefixes + * + * @param serviceUniqueName serviceUniqueName (eg.group/interfaceName:version) + * @param methodName methodName + * @param parameterTypes method parameter types + * @param categories categories + * @return metrics - key=MetricCategory value=MetricsEntityList + */ + Map> getMetricsByCategories(String serviceUniqueName, String methodName, Class[] parameterTypes, List categories); +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/service/MetricsServiceExporter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/service/MetricsServiceExporter.java new file mode 100644 index 0000000000..8a9a6a06f3 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/metrics/service/MetricsServiceExporter.java @@ -0,0 +1,47 @@ +/* + * 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.common.metrics.service; + +import org.apache.dubbo.common.extension.ExtensionScope; +import org.apache.dubbo.common.extension.SPI; + +/** + * The exporter of {@link MetricsService} + */ +@SPI(value = "default", scope = ExtensionScope.APPLICATION) +public interface MetricsServiceExporter { + + /** + * Initialize exporter + */ + void init(); + + /** + * Exports the {@link MetricsService} as a Dubbo service + * + * @return {@link MetricsServiceExporter itself} + */ + MetricsServiceExporter export(); + + /** + * Unexports the {@link MetricsService} + * + * @return {@link MetricsServiceExporter itself} + */ + MetricsServiceExporter unexport(); +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java index c4f24dfc09..389f7eb9a0 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java @@ -472,6 +472,14 @@ public class NetUtils { return address; } + public static String getLocalHostName() { + try { + return InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + return getLocalAddress().getHostName(); + } + } + /** * @param hostName * @return ip address or hostName if UnknownHostException diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/collector/DefaultMetricsCollectorTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/collector/DefaultMetricsCollectorTest.java new file mode 100644 index 0000000000..1dcd22782e --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/collector/DefaultMetricsCollectorTest.java @@ -0,0 +1,163 @@ +/* + * 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.common.metrics.collector; + +import org.apache.dubbo.common.metrics.event.MetricsEvent; +import org.apache.dubbo.common.metrics.event.RTEvent; +import org.apache.dubbo.common.metrics.event.RequestEvent; +import org.apache.dubbo.common.metrics.listener.MetricsListener; +import org.apache.dubbo.common.metrics.model.sample.GaugeMetricSample; +import org.apache.dubbo.common.metrics.model.sample.MetricSample; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY; + +public class DefaultMetricsCollectorTest { + + private ApplicationModel applicationModel; + private String interfaceName; + private String methodName; + private String group; + private String version; + + @BeforeEach + public void setup() { + ApplicationConfig config = new ApplicationConfig(); + config.setName("MockMetrics"); + + applicationModel = ApplicationModel.defaultModel(); + applicationModel.getApplicationConfigManager().setApplication(config); + + interfaceName = "org.apache.dubbo.MockInterface"; + methodName = "mockMethod"; + group = "mockGroup"; + version = "1.0.0"; + } + + @AfterEach + public void teardown() { + applicationModel.destroy(); + } + + @Test + public void testRequestsMetrics() { + DefaultMetricsCollector collector = new DefaultMetricsCollector(applicationModel); + collector.setCollectEnabled(true); + collector.increaseTotalRequests(interfaceName, methodName, group, version); + collector.increaseProcessingRequests(interfaceName, methodName, group, version); + collector.increaseSucceedRequests(interfaceName, methodName, group, version); + collector.increaseFailedRequests(interfaceName, methodName, group, version); + + List samples = collector.collect(); + for (MetricSample sample : samples) { + Assertions.assertTrue(sample instanceof GaugeMetricSample); + GaugeMetricSample gaugeSample = (GaugeMetricSample) sample; + Map tags = gaugeSample.getTags(); + Supplier supplier = gaugeSample.getSupplier(); + + Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName); + Assertions.assertEquals(tags.get(TAG_METHOD_KEY), methodName); + Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group); + Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version); + Assertions.assertEquals(supplier.get().longValue(), 1); + } + + collector.decreaseProcessingRequests(interfaceName, methodName, group, version); + samples = collector.collect(); + Map sampleMap = samples.stream().collect(Collectors.toMap(MetricSample::getName, k -> { + Number number = ((GaugeMetricSample) k).getSupplier().get(); + return number.longValue(); + })); + + Assertions.assertEquals(sampleMap.get("requests.processing"), 0L); + } + + @Test + public void testRTMetrics() { + DefaultMetricsCollector collector = new DefaultMetricsCollector(applicationModel); + collector.setCollectEnabled(true); + collector.addRT(interfaceName, methodName, group, version, 10L); + collector.addRT(interfaceName, methodName, group, version, 0L); + + List samples = collector.collect(); + for (MetricSample sample : samples) { + Map tags = sample.getTags(); + + Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName); + Assertions.assertEquals(tags.get(TAG_METHOD_KEY), methodName); + Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group); + Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version); + } + + Map sampleMap = samples.stream().collect(Collectors.toMap(MetricSample::getName, k -> { + Number number = ((GaugeMetricSample) k).getSupplier().get(); + return number.longValue(); + })); + + Assertions.assertEquals(sampleMap.get("rt.last"), 0L); + Assertions.assertEquals(sampleMap.get("rt.min"), 0L); + Assertions.assertEquals(sampleMap.get("rt.max"), 10L); + Assertions.assertEquals(sampleMap.get("rt.avg"), 5L); + Assertions.assertEquals(sampleMap.get("rt.total"), 10L); + } + + @Test + public void testListener() { + DefaultMetricsCollector collector = new DefaultMetricsCollector(applicationModel); + collector.setCollectEnabled(true); + + MockListener mockListener = new MockListener(); + collector.addListener(mockListener); + + collector.increaseTotalRequests(interfaceName, methodName, group, version); + Assertions.assertNotNull(mockListener.getCurEvent()); + Assertions.assertTrue(mockListener.getCurEvent() instanceof RequestEvent); + Assertions.assertEquals(((RequestEvent) mockListener.getCurEvent()).getType(), RequestEvent.Type.TOTAL); + + collector.addRT(interfaceName, methodName, group, version, 5L); + Assertions.assertTrue(mockListener.getCurEvent() instanceof RTEvent); + Assertions.assertEquals(((RTEvent) mockListener.getCurEvent()).getRt(), 5L); + } + + static class MockListener implements MetricsListener { + + private MetricsEvent curEvent; + + @Override + public void onEvent(MetricsEvent event) { + curEvent = event; + } + + public MetricsEvent getCurEvent() { + return curEvent; + } + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/event/RTEventTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/event/RTEventTest.java new file mode 100644 index 0000000000..fea3e0ecec --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/event/RTEventTest.java @@ -0,0 +1,35 @@ +/* + * 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.common.metrics.event; + +import org.apache.dubbo.common.metrics.model.MethodMetric; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class RTEventTest { + + @Test + public void testNewEvent() { + MethodMetric metric = new MethodMetric(); + Long rt = 5L; + RTEvent event = new RTEvent(metric, rt); + + Assertions.assertEquals(event.getSource(), metric); + Assertions.assertEquals(event.getRt(), rt); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/event/RequestEventTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/event/RequestEventTest.java new file mode 100644 index 0000000000..3da2f3ac5c --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/event/RequestEventTest.java @@ -0,0 +1,35 @@ +/* + * 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.common.metrics.event; + +import org.apache.dubbo.common.metrics.model.MethodMetric; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class RequestEventTest { + + @Test + public void testNewEvent() { + MethodMetric metric = new MethodMetric(); + RequestEvent.Type type = RequestEvent.Type.TOTAL; + RequestEvent event = new RequestEvent(metric, type); + + Assertions.assertEquals(event.getSource(), metric); + Assertions.assertEquals(event.getType(), type); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/model/MethodMetricTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/model/MethodMetricTest.java new file mode 100644 index 0000000000..f4dbcf2ded --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/model/MethodMetricTest.java @@ -0,0 +1,64 @@ +/* + * 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.common.metrics.model; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.apache.dubbo.common.constants.MetricsConstants.*; +import static org.apache.dubbo.common.utils.NetUtils.getLocalHost; +import static org.apache.dubbo.common.utils.NetUtils.getLocalHostName; + +public class MethodMetricTest { + + private static final String applicationName = null; + private static String interfaceName; + private static String methodName; + private static String group; + private static String version; + + @BeforeAll + public static void setup() { + interfaceName = "org.apache.dubbo.MockInterface"; + methodName = "mockMethod"; + group = "mockGroup"; + version = "1.0.0"; + } + + @Test + public void test() { + MethodMetric metric = new MethodMetric(applicationName, interfaceName, methodName, group, version); + Assertions.assertEquals(metric.getInterfaceName(), interfaceName); + Assertions.assertEquals(metric.getMethodName(), methodName); + Assertions.assertEquals(metric.getGroup(), group); + Assertions.assertEquals(metric.getVersion(), version); + + Map tags = metric.getTags(); + Assertions.assertEquals(tags.get(TAG_IP), getLocalHost()); + Assertions.assertEquals(tags.get(TAG_HOSTNAME), getLocalHostName()); + Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationName); + + Assertions.assertEquals(tags.get(TAG_INTERFACE_KEY), interfaceName); + Assertions.assertEquals(tags.get(TAG_METHOD_KEY), methodName); + Assertions.assertEquals(tags.get(TAG_GROUP_KEY), group); + Assertions.assertEquals(tags.get(TAG_VERSION_KEY), version); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/model/sample/GaugeMetricSampleTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/model/sample/GaugeMetricSampleTest.java new file mode 100644 index 0000000000..d45ee03c11 --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/model/sample/GaugeMetricSampleTest.java @@ -0,0 +1,61 @@ +/* + * 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.common.metrics.model.sample; + +import org.apache.dubbo.common.metrics.model.MetricsCategory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +public class GaugeMetricSampleTest { + + private static String name; + private static String description; + private static Map tags; + private static MetricsCategory category; + private static String baseUnit; + private static Supplier supplier; + + @BeforeAll + public static void setup() { + name = "test"; + description = "test"; + tags = new HashMap<>(); + category = MetricsCategory.REQUESTS; + baseUnit = "byte"; + supplier = () -> 1; + } + + @Test + public void test() { + GaugeMetricSample sample = new GaugeMetricSample(name, description, tags, category, baseUnit, supplier); + Assertions.assertEquals(sample.getName(), name); + Assertions.assertEquals(sample.getDescription(), description); + Assertions.assertEquals(sample.getTags(), tags); + Assertions.assertEquals(sample.getType(), MetricSample.Type.GAUGE); + Assertions.assertEquals(sample.getCategory(), category); + Assertions.assertEquals(sample.getBaseUnit(), baseUnit); + Assertions.assertEquals(sample.getSupplier().get(), 1); + sample.setSupplier(() -> 2); + Assertions.assertEquals(sample.getSupplier().get(), 2); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/model/sample/MetricSampleTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/model/sample/MetricSampleTest.java new file mode 100644 index 0000000000..78b575304a --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/model/sample/MetricSampleTest.java @@ -0,0 +1,57 @@ +/* + * 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.common.metrics.model.sample; + +import org.apache.dubbo.common.metrics.model.MetricsCategory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +public class MetricSampleTest { + + private static String name; + private static String description; + private static Map tags; + private static MetricSample.Type type; + private static MetricsCategory category; + private static String baseUnit; + + @BeforeAll + public static void setup() { + name = "test"; + description = "test"; + tags = new HashMap<>(); + type = MetricSample.Type.GAUGE; + category = MetricsCategory.REQUESTS; + baseUnit = "byte"; + } + + @Test + public void test() { + MetricSample sample = new MetricSample(name, description, tags, type, category, baseUnit); + Assertions.assertEquals(sample.getName(), name); + Assertions.assertEquals(sample.getDescription(), description); + Assertions.assertEquals(sample.getTags(), tags); + Assertions.assertEquals(sample.getType(), type); + Assertions.assertEquals(sample.getCategory(), category); + Assertions.assertEquals(sample.getBaseUnit(), baseUnit); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/service/MetricsEntityTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/service/MetricsEntityTest.java new file mode 100644 index 0000000000..c2688cefce --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/metrics/service/MetricsEntityTest.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.common.metrics.service; + +import org.apache.dubbo.common.metrics.model.MetricsCategory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +public class MetricsEntityTest { + + private static String name; + private static Map tags; + private static MetricsCategory category; + private static Object value; + + @BeforeAll + public static void setup() { + name = "test"; + tags = new HashMap<>(); + category = MetricsCategory.REQUESTS; + value = 1; + } + + @Test + public void test() { + MetricsEntity entity = new MetricsEntity(name, tags, category, value); + Assertions.assertEquals(entity.getName(), name); + Assertions.assertEquals(entity.getTags(), tags); + Assertions.assertEquals(entity.getCategory(), category); + Assertions.assertEquals(entity.getValue(), value); + } +}