From c91affe875a7fc500500d2e5f874caed945afde7 Mon Sep 17 00:00:00 2001 From: fomeiherz Date: Mon, 27 Mar 2023 09:48:38 +0800 Subject: [PATCH] Add metrics for configcenter (#11602) * Add ConfigCenter metrics. * Modifying the obtaining mode for ConfigCenterMetricsCollector. * Modify method name. * Add metrics when configCenter initialized. * Add UnitTest * Add License. * bugfix: config test not pass. * 1.delete author 2.unuse imported * fix configcenter metrics zk factory * Get 'dubbo.metrics.configcenter.enable' config from property, get config before startup. * resolve conflict --------- Co-authored-by: Albumen Kevin Co-authored-by: songxiaosheng --- .../common/constants/CommonConstants.java | 2 + .../common/constants/MetricsConstants.java | 6 + .../deploy/DefaultApplicationDeployer.java | 26 ++++- .../dubbo-configcenter-apollo/pom.xml | 15 +++ .../apollo/ApolloDynamicConfiguration.java | 10 +- .../ApolloDynamicConfigurationFactory.java | 10 +- .../ApolloDynamicConfigurationTest.java | 11 +- .../dubbo-configcenter-nacos/pom.xml | 15 +++ .../nacos/NacosDynamicConfiguration.java | 13 ++- .../NacosDynamicConfigurationFactory.java | 9 +- .../nacos/NacosDynamicConfigurationTest.java | 12 +- .../configcenter/support/nacos/RetryTest.java | 13 ++- .../dubbo-configcenter-zookeeper/pom.xml | 15 +++ .../support/zookeeper/CacheListener.java | 5 +- .../zookeeper/ZookeeperDataListener.java | 19 +++- .../ZookeeperDynamicConfiguration.java | 7 +- .../ZookeeperDynamicConfigurationFactory.java | 5 +- dubbo-metrics/dubbo-metrics-api/pom.xml | 5 + .../metrics/model/ConfigCenterMetric.java | 88 +++++++++++++++ .../dubbo/metrics/model/MetricsCategory.java | 3 +- .../dubbo/metrics/model/MetricsKey.java | 2 + .../ConfigCenterMetricsCollector.java | 99 +++++++++++++++++ .../ConfigCenterMetricsCollectorTest.java | 104 ++++++++++++++++++ 23 files changed, 457 insertions(+), 37 deletions(-) create mode 100644 dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ConfigCenterMetric.java create mode 100644 dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/ConfigCenterMetricsCollector.java create mode 100644 dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/ConfigCenterMetricsCollectorTest.java diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java index 6a723f78a4..c8f1ab7a9e 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java @@ -626,4 +626,6 @@ public interface CommonConstants { String BYTE_ACCESSOR_KEY = "byte.accessor"; String PAYLOAD = "payload"; + + String DUBBO_METRICS_CONFIGCENTER_ENABLE = "dubbo.metrics.configcenter.enable"; } 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 89e0333b36..58b6b39887 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 @@ -37,6 +37,12 @@ public interface MetricsConstants { String TAG_VERSION_KEY = "version"; String TAG_APPLICATION_VERSION_KEY = "application.version"; + + String TAG_KEY_KEY = "key"; + + String TAG_CONFIG_CENTER = "config.center"; + + String TAG_CHANGE_TYPE = "change.type"; String ENABLE_JVM_METRICS_KEY = "enable.jvm.metrics"; diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java index 12d29ff2e5..c933e43b42 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java @@ -50,6 +50,7 @@ import org.apache.dubbo.config.utils.CompositeReferenceCache; import org.apache.dubbo.config.utils.ConfigValidationUtils; import org.apache.dubbo.metadata.report.MetadataReportFactory; import org.apache.dubbo.metadata.report.MetadataReportInstance; +import org.apache.dubbo.metrics.collector.ConfigCenterMetricsCollector; import org.apache.dubbo.metrics.collector.DefaultMetricsCollector; import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster; import org.apache.dubbo.metrics.model.TimePair; @@ -782,20 +783,33 @@ public class DefaultApplicationDeployer extends AbstractDeployer configMap = parseProperties(configContent); + Map appConfigMap = parseProperties(appConfigContent); + + environment.updateExternalConfigMap(configMap); + environment.updateAppExternalConfigMap(appConfigMap); + + // Add metrics + collector.increase4Initialized(configCenter.getConfigFile(), configCenter.getGroup(), + configCenter.getProtocol(), applicationModel.getApplicationName(), configMap.size()); + if (isNotEmpty(appGroup)) { + collector.increase4Initialized(appConfigFile, appGroup, + configCenter.getProtocol(), applicationModel.getApplicationName(), appConfigMap.size()); + } } catch (IOException e) { throw new IllegalStateException("Failed to parse configurations from Config Center.", e); } diff --git a/dubbo-configcenter/dubbo-configcenter-apollo/pom.xml b/dubbo-configcenter/dubbo-configcenter-apollo/pom.xml index d31dc785be..5b86955599 100644 --- a/dubbo-configcenter/dubbo-configcenter-apollo/pom.xml +++ b/dubbo-configcenter/dubbo-configcenter-apollo/pom.xml @@ -38,6 +38,21 @@ dubbo-common ${project.parent.version} + + org.apache.dubbo + dubbo-metrics-api + ${project.parent.version} + + + org.apache.dubbo + dubbo-metrics-default + ${project.parent.version} + + + org.apache.dubbo + dubbo-metrics-prometheus + ${project.parent.version} + com.ctrip.framework.apollo apollo-client diff --git a/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java index 9525f7ce7e..1b33e85781 100644 --- a/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java +++ b/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java @@ -33,6 +33,8 @@ import com.ctrip.framework.apollo.core.enums.ConfigFileFormat; import com.ctrip.framework.apollo.enums.ConfigSourceType; import com.ctrip.framework.apollo.enums.PropertyChangeType; import com.ctrip.framework.apollo.model.ConfigChange; +import org.apache.dubbo.metrics.collector.ConfigCenterMetricsCollector; +import org.apache.dubbo.rpc.model.ApplicationModel; import java.util.Arrays; import java.util.Collections; @@ -76,9 +78,11 @@ public class ApolloDynamicConfiguration implements DynamicConfiguration { private final Config dubboConfig; private final ConfigFile dubboConfigFile; private final ConcurrentMap listeners = new ConcurrentHashMap<>(); + private final ApplicationModel applicationModel; - ApolloDynamicConfiguration(URL url) { + ApolloDynamicConfiguration(URL url, ApplicationModel applicationModel) { this.url = url; + this.applicationModel = applicationModel; // Instead of using Dubbo's configuration, I would suggest use the original configuration method Apollo provides. String configEnv = url.getParameter(APOLLO_ENV_KEY); String configAddr = getAddressWithProtocolPrefix(url); @@ -245,6 +249,10 @@ public class ApolloDynamicConfiguration implements DynamicConfiguration { ConfigChangedEvent event = new ConfigChangedEvent(key, change.getNamespace(), change.getNewValue(), getChangeType(change)); listeners.forEach(listener -> listener.process(event)); + + ConfigCenterMetricsCollector collector = + applicationModel.getBeanFactory().getBean(ConfigCenterMetricsCollector.class); + collector.increaseUpdated("apollo", applicationModel.getApplicationName(), event); } } diff --git a/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfigurationFactory.java b/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfigurationFactory.java index 6a8ce304f4..64331d886b 100644 --- a/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfigurationFactory.java +++ b/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfigurationFactory.java @@ -19,13 +19,21 @@ package org.apache.dubbo.configcenter.support.apollo; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory; import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; +import org.apache.dubbo.rpc.model.ApplicationModel; /** * */ public class ApolloDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory { + + private ApplicationModel applicationModel; + + public ApolloDynamicConfigurationFactory(ApplicationModel applicationModel) { + this.applicationModel = applicationModel; + } + @Override protected DynamicConfiguration createDynamicConfiguration(URL url) { - return new ApolloDynamicConfiguration(url); + return new ApolloDynamicConfiguration(url, applicationModel); } } diff --git a/dubbo-configcenter/dubbo-configcenter-apollo/src/test/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfigurationTest.java b/dubbo-configcenter/dubbo-configcenter-apollo/src/test/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfigurationTest.java index a54ffd37ad..07aa131e67 100644 --- a/dubbo-configcenter/dubbo-configcenter-apollo/src/test/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfigurationTest.java +++ b/dubbo-configcenter/dubbo-configcenter-apollo/src/test/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfigurationTest.java @@ -21,6 +21,7 @@ import org.apache.dubbo.common.config.configcenter.ConfigChangeType; import org.apache.dubbo.common.config.configcenter.ConfigurationListener; import com.google.common.util.concurrent.SettableFuture; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -46,6 +47,7 @@ class ApolloDynamicConfigurationTest { private static final String DEFAULT_NAMESPACE = "dubbo"; private static ApolloDynamicConfiguration apolloDynamicConfiguration; private static URL url; + private static ApplicationModel applicationModel; /** * The constant embeddedApollo. @@ -61,6 +63,7 @@ class ApolloDynamicConfigurationTest { String apolloUrl = System.getProperty("apollo.configService"); String urlForDubbo = "apollo://" + apolloUrl.substring(apolloUrl.lastIndexOf("/") + 1) + "/org.apache.dubbo.apollo.testService?namespace=dubbo&check=true"; url = URL.valueOf(urlForDubbo).addParameter(SESSION_TIMEOUT_KEY, 15000); + applicationModel = ApplicationModel.defaultModel(); } // /** @@ -88,7 +91,7 @@ class ApolloDynamicConfigurationTest { String mockKey = "mockKey1"; String mockValue = String.valueOf(new Random().nextInt()); putMockRuleData(mockKey, mockValue, DEFAULT_NAMESPACE); - apolloDynamicConfiguration = new ApolloDynamicConfiguration(url); + apolloDynamicConfiguration = new ApolloDynamicConfiguration(url, applicationModel); assertEquals(mockValue, apolloDynamicConfiguration.getConfig(mockKey, DEFAULT_NAMESPACE, 3000L)); mockKey = "notExistKey"; @@ -106,7 +109,7 @@ class ApolloDynamicConfigurationTest { String mockValue = String.valueOf(new Random().nextInt()); putMockRuleData(mockKey, mockValue, DEFAULT_NAMESPACE); TimeUnit.MILLISECONDS.sleep(1000); - apolloDynamicConfiguration = new ApolloDynamicConfiguration(url); + apolloDynamicConfiguration = new ApolloDynamicConfiguration(url, applicationModel); assertEquals(mockValue, apolloDynamicConfiguration.getInternalProperty(mockKey)); mockValue = "mockValue2"; @@ -129,7 +132,7 @@ class ApolloDynamicConfigurationTest { final SettableFuture future = SettableFuture.create(); - apolloDynamicConfiguration = new ApolloDynamicConfiguration(url); + apolloDynamicConfiguration = new ApolloDynamicConfiguration(url, applicationModel); apolloDynamicConfiguration.addListener(mockKey, DEFAULT_NAMESPACE, new ConfigurationListener() { @Override @@ -187,4 +190,4 @@ class ApolloDynamicConfigurationTest { } -} \ No newline at end of file +} diff --git a/dubbo-configcenter/dubbo-configcenter-nacos/pom.xml b/dubbo-configcenter/dubbo-configcenter-nacos/pom.xml index 65364b8bed..a6bc25f483 100644 --- a/dubbo-configcenter/dubbo-configcenter-nacos/pom.xml +++ b/dubbo-configcenter/dubbo-configcenter-nacos/pom.xml @@ -41,5 +41,20 @@ com.alibaba.nacos nacos-client + + org.apache.dubbo + dubbo-metrics-api + ${project.parent.version} + + + org.apache.dubbo + dubbo-metrics-default + ${project.parent.version} + + + org.apache.dubbo + dubbo-metrics-prometheus + ${project.parent.version} + diff --git a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java index 359d33770a..9a8e42b2bb 100644 --- a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java +++ b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java @@ -43,6 +43,8 @@ import com.alibaba.nacos.api.PropertyKeyConst; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.listener.AbstractSharedListener; import com.alibaba.nacos.api.exception.NacosException; +import org.apache.dubbo.metrics.collector.ConfigCenterMetricsCollector; +import org.apache.dubbo.rpc.model.ApplicationModel; import static com.alibaba.nacos.api.PropertyKeyConst.PASSWORD; import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR; @@ -80,6 +82,8 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { */ private final NacosConfigServiceWrapper configService; + private ApplicationModel applicationModel; + /** * The map store the key to {@link NacosConfigListener} mapping */ @@ -87,10 +91,11 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { private final MD5Utils md5Utils = new MD5Utils(); - NacosDynamicConfiguration(URL url) { + NacosDynamicConfiguration(URL url, ApplicationModel applicationModel) { this.nacosProperties = buildNacosProperties(url); this.configService = buildConfigService(url); - watchListenerMap = new ConcurrentHashMap<>(); + this.watchListenerMap = new ConcurrentHashMap<>(); + this.applicationModel = applicationModel; } private NacosConfigServiceWrapper buildConfigService(URL url) { @@ -339,6 +344,10 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { cacheData.put(dataId, configInfo); } listeners.forEach(listener -> listener.process(event)); + + ConfigCenterMetricsCollector collector = + applicationModel.getBeanFactory().getOrRegisterBean(ConfigCenterMetricsCollector.class); + collector.increaseUpdated("nacos", applicationModel.getApplicationName(), event); } void addListener(ConfigurationListener configurationListener) { diff --git a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationFactory.java b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationFactory.java index 61c02b48cf..5d2196726d 100644 --- a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationFactory.java +++ b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationFactory.java @@ -23,12 +23,19 @@ import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; import org.apache.dubbo.common.constants.CommonConstants; import com.alibaba.nacos.api.PropertyKeyConst; +import org.apache.dubbo.rpc.model.ApplicationModel; /** * The nacos implementation of {@link AbstractDynamicConfigurationFactory} */ public class NacosDynamicConfigurationFactory extends AbstractDynamicConfigurationFactory { + private ApplicationModel applicationModel; + + public NacosDynamicConfigurationFactory(ApplicationModel applicationModel) { + this.applicationModel = applicationModel; + } + @Override protected DynamicConfiguration createDynamicConfiguration(URL url) { URL nacosURL = url; @@ -36,6 +43,6 @@ public class NacosDynamicConfigurationFactory extends AbstractDynamicConfigurati // Nacos use empty string as default name space, replace default namespace "dubbo" to "" nacosURL = url.removeParameter(PropertyKeyConst.NAMESPACE); } - return new NacosDynamicConfiguration(nacosURL); + return new NacosDynamicConfiguration(nacosURL, applicationModel); } } diff --git a/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationTest.java b/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationTest.java index 3f2bb525fd..831c74c833 100644 --- a/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationTest.java +++ b/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfigurationTest.java @@ -17,14 +17,14 @@ package org.apache.dubbo.configcenter.support.nacos; +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.exception.NacosException; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent; import org.apache.dubbo.common.config.configcenter.ConfigurationListener; import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; - -import com.alibaba.nacos.api.NacosFactory; -import com.alibaba.nacos.api.config.ConfigService; -import com.alibaba.nacos.api.exception.NacosException; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; @@ -132,7 +132,7 @@ class NacosDynamicConfigurationTest { // timeout in 15 seconds. URL url = URL.valueOf(urlForDubbo) .addParameter(SESSION_TIMEOUT_KEY, 15000); - config = new NacosDynamicConfiguration(url); + config = new NacosDynamicConfiguration(url, ApplicationModel.defaultModel()); try { @@ -184,4 +184,4 @@ class NacosDynamicConfigurationTest { } } -} \ No newline at end of file +} diff --git a/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/RetryTest.java b/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/RetryTest.java index 3be9037380..32116ba247 100644 --- a/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/RetryTest.java +++ b/dubbo-configcenter/dubbo-configcenter-nacos/src/test/java/org/apache/dubbo/configcenter/support/nacos/RetryTest.java @@ -20,6 +20,7 @@ import java.util.Properties; import java.util.concurrent.atomic.AtomicInteger; import org.apache.dubbo.common.URL; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; @@ -34,6 +35,8 @@ import static com.alibaba.nacos.client.constant.Constants.HealthCheck.UP; import static org.mockito.ArgumentMatchers.any; class RetryTest { + + private static ApplicationModel applicationModel = ApplicationModel.defaultModel(); @Test void testRetryCreate() { @@ -51,10 +54,10 @@ class RetryTest { URL url = URL.valueOf("nacos://127.0.0.1:8848") .addParameter("nacos.retry", 5) .addParameter("nacos.retry-wait", 10); - Assertions.assertThrows(IllegalStateException.class, () -> new NacosDynamicConfiguration(url)); + Assertions.assertThrows(IllegalStateException.class, () -> new NacosDynamicConfiguration(url, applicationModel)); try { - new NacosDynamicConfiguration(url); + new NacosDynamicConfiguration(url, applicationModel); } catch (Throwable t) { Assertions.fail(t); } @@ -78,7 +81,7 @@ class RetryTest { .addParameter("nacos.retry-wait", 10) .addParameter("nacos.check", "false"); try { - new NacosDynamicConfiguration(url); + new NacosDynamicConfiguration(url, applicationModel); } catch (Throwable t) { Assertions.fail(t); } @@ -110,10 +113,10 @@ class RetryTest { URL url = URL.valueOf("nacos://127.0.0.1:8848") .addParameter("nacos.retry", 5) .addParameter("nacos.retry-wait", 10); - Assertions.assertThrows(IllegalStateException.class, () -> new NacosDynamicConfiguration(url)); + Assertions.assertThrows(IllegalStateException.class, () -> new NacosDynamicConfiguration(url, applicationModel)); try { - new NacosDynamicConfiguration(url); + new NacosDynamicConfiguration(url, applicationModel); } catch (Throwable t) { Assertions.fail(t); } diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/pom.xml b/dubbo-configcenter/dubbo-configcenter-zookeeper/pom.xml index 8166ca072d..825fbbb289 100644 --- a/dubbo-configcenter/dubbo-configcenter-zookeeper/pom.xml +++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/pom.xml @@ -60,6 +60,21 @@ org.apache.zookeeper zookeeper + + org.apache.dubbo + dubbo-metrics-api + ${project.parent.version} + + + org.apache.dubbo + dubbo-metrics-default + ${project.parent.version} + + + org.apache.dubbo + dubbo-metrics-prometheus + ${project.parent.version} + diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/CacheListener.java b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/CacheListener.java index 7ae31afca0..df596926b7 100644 --- a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/CacheListener.java +++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/CacheListener.java @@ -19,6 +19,7 @@ package org.apache.dubbo.configcenter.support.zookeeper; import org.apache.dubbo.common.config.configcenter.ConfigurationListener; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.ConcurrentHashMapUtils; +import org.apache.dubbo.rpc.model.ApplicationModel; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -34,9 +35,9 @@ public class CacheListener { public CacheListener() { } - public ZookeeperDataListener addListener(String pathKey, ConfigurationListener configurationListener, String key, String group) { + public ZookeeperDataListener addListener(String pathKey, ConfigurationListener configurationListener, String key, String group, ApplicationModel applicationModel) { ZookeeperDataListener zookeeperDataListener = ConcurrentHashMapUtils.computeIfAbsent(pathKeyListeners, pathKey, - _pathKey -> new ZookeeperDataListener(_pathKey, key, group)); + _pathKey -> new ZookeeperDataListener(_pathKey, key, group, applicationModel)); zookeeperDataListener.addListener(configurationListener); return zookeeperDataListener; } diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDataListener.java b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDataListener.java index 22243d55ed..a21babe2a2 100644 --- a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDataListener.java +++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDataListener.java @@ -20,8 +20,10 @@ import org.apache.dubbo.common.config.configcenter.ConfigChangeType; import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent; import org.apache.dubbo.common.config.configcenter.ConfigurationListener; import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.metrics.collector.ConfigCenterMetricsCollector; import org.apache.dubbo.remoting.zookeeper.DataListener; import org.apache.dubbo.remoting.zookeeper.EventType; +import org.apache.dubbo.rpc.model.ApplicationModel; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; @@ -30,16 +32,19 @@ import java.util.concurrent.CopyOnWriteArraySet; * one path has multi configurationListeners */ public class ZookeeperDataListener implements DataListener { - private final String path; - private final String key; - private final String group; - private final Set listeners; - public ZookeeperDataListener(String path, String key, String group) { + private String path; + private String key; + private String group; + private Set listeners; + private ApplicationModel applicationModel; + + public ZookeeperDataListener(String path, String key, String group, ApplicationModel applicationModel) { this.path = path; this.key = key; this.group = group; this.listeners = new CopyOnWriteArraySet<>(); + this.applicationModel = applicationModel; } public void addListener(ConfigurationListener configurationListener) { @@ -71,6 +76,10 @@ public class ZookeeperDataListener implements DataListener { if (CollectionUtils.isNotEmpty(listeners)) { listeners.forEach(listener -> listener.process(configChangeEvent)); } + + ConfigCenterMetricsCollector collector = + applicationModel.getBeanFactory().getBean(ConfigCenterMetricsCollector.class); + collector.increaseUpdated("zookeeper", applicationModel.getApplicationName(), configChangeEvent); } } diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java index 423c2834f6..e0bc325c4c 100644 --- a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java +++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java @@ -26,6 +26,7 @@ import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.remoting.zookeeper.ZookeeperClient; import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.zookeeper.data.Stat; import java.util.Collection; @@ -47,11 +48,13 @@ public class ZookeeperDynamicConfiguration extends TreePathDynamicConfiguration private static final int DEFAULT_ZK_EXECUTOR_THREADS_NUM = 1; private static final int DEFAULT_QUEUE = 10000; private static final Long THREAD_KEEP_ALIVE_TIME = 0L; + private final ApplicationModel applicationModel; - ZookeeperDynamicConfiguration(URL url, ZookeeperTransporter zookeeperTransporter) { + ZookeeperDynamicConfiguration(URL url, ZookeeperTransporter zookeeperTransporter, ApplicationModel applicationModel) { super(url); this.cacheListener = new CacheListener(); + this.applicationModel = applicationModel; final String threadName = this.getClass().getSimpleName(); this.executor = new ThreadPoolExecutor(DEFAULT_ZK_EXECUTOR_THREADS_NUM, DEFAULT_ZK_EXECUTOR_THREADS_NUM, @@ -150,7 +153,7 @@ public class ZookeeperDynamicConfiguration extends TreePathDynamicConfiguration if (cachedListener != null) { cachedListener.addListener(listener); } else { - ZookeeperDataListener addedListener = cacheListener.addListener(pathKey, listener, key, group); + ZookeeperDataListener addedListener = cacheListener.addListener(pathKey, listener, key, group, applicationModel); zkClient.addDataListener(pathKey, addedListener, executor); } } diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationFactory.java b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationFactory.java index f470654ca5..1ab7497379 100644 --- a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationFactory.java +++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationFactory.java @@ -26,12 +26,15 @@ public class ZookeeperDynamicConfigurationFactory extends AbstractDynamicConfigu private final ZookeeperTransporter zookeeperTransporter; + private final ApplicationModel applicationModel; + public ZookeeperDynamicConfigurationFactory(ApplicationModel applicationModel) { + this.applicationModel = applicationModel; this.zookeeperTransporter = ZookeeperTransporter.getExtension(applicationModel); } @Override protected DynamicConfiguration createDynamicConfiguration(URL url) { - return new ZookeeperDynamicConfiguration(url, zookeeperTransporter); + return new ZookeeperDynamicConfiguration(url, zookeeperTransporter, applicationModel); } } diff --git a/dubbo-metrics/dubbo-metrics-api/pom.xml b/dubbo-metrics/dubbo-metrics-api/pom.xml index 3c31ae389c..a35c238395 100644 --- a/dubbo-metrics/dubbo-metrics-api/pom.xml +++ b/dubbo-metrics/dubbo-metrics-api/pom.xml @@ -49,5 +49,10 @@ com.tdunning t-digest + + io.micrometer + micrometer-tracing-integration-test + test + diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ConfigCenterMetric.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ConfigCenterMetric.java new file mode 100644 index 0000000000..a6f9987e03 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ConfigCenterMetric.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dubbo.metrics.model; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_CHANGE_TYPE; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_CONFIG_CENTER; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_KEY_KEY; +import static org.apache.dubbo.common.utils.NetUtils.getLocalHost; +import static org.apache.dubbo.common.utils.NetUtils.getLocalHostName; + +public class ConfigCenterMetric implements Metric { + + private String applicationName; + private String key; + private String group; + private String configCenter; + private String changeType; + + public ConfigCenterMetric() { + + } + + public ConfigCenterMetric(String applicationName, String key, String group, String configCenter, String changeType) { + this.applicationName = applicationName; + this.key = key; + this.group = group; + this.configCenter = configCenter; + this.changeType = changeType; + } + + @Override + 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_KEY_KEY, key); + tags.put(TAG_GROUP_KEY, group); + tags.put(TAG_CONFIG_CENTER, configCenter); + tags.put(TAG_CHANGE_TYPE, changeType.toLowerCase()); + + return tags; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ConfigCenterMetric that = (ConfigCenterMetric) o; + + if (!Objects.equals(applicationName, that.applicationName)) + return false; + if (!Objects.equals(key, that.key)) return false; + if (!Objects.equals(group, that.group)) return false; + if (!Objects.equals(configCenter, that.configCenter)) return false; + return Objects.equals(changeType, that.changeType); + } + + @Override + public int hashCode() { + return Objects.hash(applicationName, key, group, configCenter, changeType); + } +} 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 990044374b..0eecdda807 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 @@ -24,8 +24,9 @@ public enum MetricsCategory { RT, QPS, REQUESTS, + APPLICATION, + CONFIGCENTER, REGISTRY, METADATA, THREAD_POOL, - APPLICATION } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKey.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKey.java index 2592f706cd..6065ee5289 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKey.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsKey.java @@ -20,6 +20,8 @@ package org.apache.dubbo.metrics.model; public enum MetricsKey { APPLICATION_METRIC_INFO("dubbo.application.info.total", "Total Application Info"), + CONFIGCENTER_METRIC_TOTAL("dubbo.configcenter.total", "Config Changed Total"), + // provider metrics key METRIC_REQUESTS("dubbo.%s.requests.total", "Total Requests"), METRIC_REQUESTS_SUCCEED("dubbo.%s.requests.succeed.total", "Total Succeed Requests"), diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/ConfigCenterMetricsCollector.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/ConfigCenterMetricsCollector.java new file mode 100644 index 0000000000..1170243e28 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/ConfigCenterMetricsCollector.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dubbo.metrics.collector; + +import org.apache.dubbo.common.config.configcenter.ConfigChangeType; +import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent; +import org.apache.dubbo.metrics.model.ConfigCenterMetric; +import org.apache.dubbo.metrics.model.MetricsKey; +import org.apache.dubbo.metrics.model.sample.GaugeMetricSample; +import org.apache.dubbo.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.AtomicLong; + +import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_METRICS_CONFIGCENTER_ENABLE; +import static org.apache.dubbo.metrics.model.MetricsCategory.CONFIGCENTER; + +public class ConfigCenterMetricsCollector implements MetricsCollector { + + private boolean collectEnabled = true; + private final ApplicationModel applicationModel; + + private final Map updatedMetrics = new ConcurrentHashMap<>(); + + public ConfigCenterMetricsCollector(ApplicationModel applicationModel) { + this.applicationModel = applicationModel; + // default is true, disable when config false + if ("false".equals(System.getProperty(DUBBO_METRICS_CONFIGCENTER_ENABLE))) { + collectEnabled = false; + } + } + + public void setCollectEnabled(Boolean collectEnabled) { + if (collectEnabled != null) { + this.collectEnabled = collectEnabled; + } + } + + @Override + public boolean isCollectEnabled() { + return collectEnabled; + } + + public void increase4Initialized(String key, String group, String protocol, String applicationName, int count) { + if (!isCollectEnabled()) { + return; + } + if (count <= 0) { + return; + } + ConfigCenterMetric metric = new ConfigCenterMetric(applicationName, key, group, protocol, ConfigChangeType.ADDED.name()); + AtomicLong aLong = updatedMetrics.computeIfAbsent(metric, k -> new AtomicLong(0L)); + aLong.addAndGet(count); + } + + public void increaseUpdated(String protocol, String applicationName, ConfigChangedEvent event) { + if (!isCollectEnabled()) { + return; + } + ConfigCenterMetric metric = new ConfigCenterMetric(applicationName, event.getKey(), event.getGroup(), protocol, event.getChangeType().name()); + AtomicLong count = updatedMetrics.computeIfAbsent(metric, k -> new AtomicLong(0L)); + count.incrementAndGet(); + } + + @Override + public List collect() { + // Add metrics to reporter + List list = new ArrayList<>(); + if (!isCollectEnabled()) { + return list; + } + collect(list); + return list; + } + + private void collect(List list) { + updatedMetrics.forEach((k, v) -> list.add(new GaugeMetricSample<>(MetricsKey.CONFIGCENTER_METRIC_TOTAL, k.getTags(), CONFIGCENTER, v, AtomicLong::get))); + } + +} diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/ConfigCenterMetricsCollectorTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/ConfigCenterMetricsCollectorTest.java new file mode 100644 index 0000000000..e234279339 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/ConfigCenterMetricsCollectorTest.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dubbo.metrics.collector; + +import org.apache.dubbo.common.config.configcenter.ConfigChangeType; +import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.metrics.model.ConfigCenterMetric; +import org.apache.dubbo.metrics.model.sample.GaugeMetricSample; +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.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 static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY; +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_VERSION_KEY; +import static org.junit.jupiter.api.Assertions.*; + +class ConfigCenterMetricsCollectorTest { + + private FrameworkModel frameworkModel; + private ApplicationModel applicationModel; + + @BeforeEach + public void setup() { + frameworkModel = FrameworkModel.defaultModel(); + applicationModel = frameworkModel.newApplication(); + ApplicationConfig config = new ApplicationConfig(); + config.setName("MockMetrics"); + + applicationModel.getApplicationConfigManager().setApplication(config); + } + + @AfterEach + public void teardown() { + applicationModel.destroy(); + } + + @Test + void increase4Initialized() { + ConfigCenterMetricsCollector collector = new ConfigCenterMetricsCollector(applicationModel); + collector.setCollectEnabled(true); + String applicationName = applicationModel.getApplicationName(); + collector.increase4Initialized("key", "group", "nacos", applicationName, 1); + collector.increase4Initialized("key", "group", "nacos", applicationName, 1); + + List samples = collector.collect(); + for (MetricSample sample : samples) { + Assertions.assertTrue(sample instanceof GaugeMetricSample); + GaugeMetricSample gaugeSample = (GaugeMetricSample) sample; + Map tags = gaugeSample.getTags(); + + Assertions.assertEquals(gaugeSample.applyAsLong(), 2); + Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationName); + } + } + + @Test + void increaseUpdated() { + ConfigCenterMetricsCollector collector = new ConfigCenterMetricsCollector(applicationModel); + collector.setCollectEnabled(true); + String applicationName = applicationModel.getApplicationName(); + + ConfigChangedEvent event = new ConfigChangedEvent("key", "group", null, ConfigChangeType.ADDED); + + collector.increaseUpdated("nacos", applicationName, event); + collector.increaseUpdated("nacos", applicationName, event); + + List samples = collector.collect(); + for (MetricSample sample : samples) { + Assertions.assertTrue(sample instanceof GaugeMetricSample); + GaugeMetricSample gaugeSample = (GaugeMetricSample) sample; + Map tags = gaugeSample.getTags(); + + Assertions.assertEquals(gaugeSample.applyAsLong(), 2); + Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationName); + } + } +}