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 <jhq0812@gmail.com> Co-authored-by: songxiaosheng <songxiaosheng@elastic.link>
This commit is contained in:
parent
4a3172b80a
commit
c91affe875
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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<ApplicationMode
|
|||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
ApplicationModel applicationModel = getApplicationModel();
|
||||
ConfigCenterMetricsCollector collector =
|
||||
applicationModel.getBeanFactory().getOrRegisterBean(ConfigCenterMetricsCollector.class);
|
||||
|
||||
if (StringUtils.isNotEmpty(configCenter.getConfigFile())) {
|
||||
String configContent = dynamicConfiguration.getProperties(configCenter.getConfigFile(), configCenter.getGroup());
|
||||
String appGroup = getApplication().getName();
|
||||
String appConfigContent = null;
|
||||
String appConfigFile = null;
|
||||
if (isNotEmpty(appGroup)) {
|
||||
appConfigContent = dynamicConfiguration.getProperties
|
||||
(isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile(),
|
||||
appGroup
|
||||
);
|
||||
appConfigFile = isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile();
|
||||
appConfigContent = dynamicConfiguration.getProperties(appConfigFile, appGroup);
|
||||
}
|
||||
try {
|
||||
environment.updateExternalConfigMap(parseProperties(configContent));
|
||||
environment.updateAppExternalConfigMap(parseProperties(appConfigContent));
|
||||
Map<String, String> configMap = parseProperties(configContent);
|
||||
Map<String, String> 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,21 @@
|
|||
<artifactId>dubbo-common</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metrics-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metrics-default</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metrics-prometheus</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ctrip.framework.apollo</groupId>
|
||||
<artifactId>apollo-client</artifactId>
|
||||
|
|
|
|||
|
|
@ -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<String, ApolloListener> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<org.apache.dubbo.common.config.configcenter.ConfigChangedEvent> 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 {
|
|||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,5 +41,20 @@
|
|||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metrics-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metrics-default</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metrics-prometheus</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,21 @@
|
|||
<groupId>org.apache.zookeeper</groupId>
|
||||
<artifactId>zookeeper</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metrics-api</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metrics-default</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-metrics-prometheus</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ConfigurationListener> listeners;
|
||||
|
||||
public ZookeeperDataListener(String path, String key, String group) {
|
||||
private String path;
|
||||
private String key;
|
||||
private String group;
|
||||
private Set<ConfigurationListener> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,5 +49,10 @@
|
|||
<groupId>com.tdunning</groupId>
|
||||
<artifactId>t-digest</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-tracing-integration-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -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<String, String> getTags() {
|
||||
Map<String, String> 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -24,8 +24,9 @@ public enum MetricsCategory {
|
|||
RT,
|
||||
QPS,
|
||||
REQUESTS,
|
||||
APPLICATION,
|
||||
CONFIGCENTER,
|
||||
REGISTRY,
|
||||
METADATA,
|
||||
THREAD_POOL,
|
||||
APPLICATION
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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<ConfigCenterMetric, AtomicLong> 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<MetricSample> collect() {
|
||||
// Add metrics to reporter
|
||||
List<MetricSample> list = new ArrayList<>();
|
||||
if (!isCollectEnabled()) {
|
||||
return list;
|
||||
}
|
||||
collect(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
private void collect(List<MetricSample> list) {
|
||||
updatedMetrics.forEach((k, v) -> list.add(new GaugeMetricSample<>(MetricsKey.CONFIGCENTER_METRIC_TOTAL, k.getTags(), CONFIGCENTER, v, AtomicLong::get)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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<MetricSample> samples = collector.collect();
|
||||
for (MetricSample sample : samples) {
|
||||
Assertions.assertTrue(sample instanceof GaugeMetricSample);
|
||||
GaugeMetricSample<Long> gaugeSample = (GaugeMetricSample) sample;
|
||||
Map<String, String> 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<MetricSample> samples = collector.collect();
|
||||
for (MetricSample sample : samples) {
|
||||
Assertions.assertTrue(sample instanceof GaugeMetricSample);
|
||||
GaugeMetricSample<Long> gaugeSample = (GaugeMetricSample) sample;
|
||||
Map<String, String> tags = gaugeSample.getTags();
|
||||
|
||||
Assertions.assertEquals(gaugeSample.applyAsLong(), 2);
|
||||
Assertions.assertEquals(tags.get(TAG_APPLICATION_NAME), applicationName);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue