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

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new 5c2418e  Support nacos grouped dynamic configurations. (#7632)
5c2418e is described below

commit 5c2418ee9d9c0c33b76b29717c36168f9040cb0f
Author: wankai123 <[email protected]>
AuthorDate: Wed Sep 1 21:22:06 2021 +0800

    Support nacos grouped dynamic configurations. (#7632)
---
 CHANGES.md                                         |  1 +
 docs/en/setup/backend/dynamic-config-nacos.md      | 63 +++++++++++++++++++++-
 .../nacos/NacosConfigWatcherRegister.java          | 41 ++++++++++----
 .../nacos/NacosConfigurationProvider.java          |  8 ++-
 .../nacos/ITNacosConfigurationTest.java            | 52 ++++++++++++++++--
 .../nacos/NacosConfigurationTestProvider.java      | 38 +++++++++++--
 6 files changed, 178 insertions(+), 25 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index aaeefb1..07f248c 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -49,6 +49,7 @@ Release Notes.
 * Fix dynamic configuration watch implementation current value not null when 
the config is deleted.
 * Fix `LoggingConfigWatcher` return `watch.value` would not consistent with 
the real configuration content.
 * Fix `ZookeeperConfigWatcherRegister.readConfig()` could cause `NPE` when 
`data.getData()` is null.
+* Support nacos grouped dynamic configurations.
 
 #### UI
 
diff --git a/docs/en/setup/backend/dynamic-config-nacos.md 
b/docs/en/setup/backend/dynamic-config-nacos.md
index a7a8a52..73562b1 100755
--- a/docs/en/setup/backend/dynamic-config-nacos.md
+++ b/docs/en/setup/backend/dynamic-config-nacos.md
@@ -18,4 +18,65 @@ configuration:
     period: ${SW_CONFIG_NACOS_PERIOD:60}
     # the name of current cluster, set the name if you want to upstream system 
known.
     clusterName: ${SW_CONFIG_NACOS_CLUSTER_NAME:default}
-```
\ No newline at end of file
+```
+
+## Config Storage
+### Single Config
+
+| Data Id | Group | Config Value |
+|-----|-----|-----|
+| configKey | {group} | configValue |
+
+e.g. The config is:
+```
+{agent-analyzer.default.slowDBAccessThreshold}:{default:200,mongodb:50}
+```
+If `group = skywalking` the config in nacos is:
+
+| Data Id | Group | Config Value |
+|-----|-----|-----|
+| agent-analyzer.default.slowDBAccessThreshold | skywalking | 
default:200,mongodb:50 |
+
+### Group Config
+
+| Data Id | Group | Config Value | Config Type |
+|-----|-----|-----|-----|
+| configKey | {group} | subItemkey1</br>subItemkey2</br>... | TEXT |
+| subItemkey1 | {group} | subItemValue1 |
+| subItemkey2 | {group} | subItemValue2 |
+| ... | ... | ... |
+
+Notice: If you add/remove a subItem, you need to add/remove the subItemKey 
from the group which the subItem belongs:
+
+| Data Id | Group | Config Value | Config Type |
+|-----|-----|-----|-----|
+| configKey | {group} | subItemkey1</br>subItemkey2</br>... | TEXT |
+
+We separate subItemkeys by `\n` or `\r\n`, trim leading and trailing 
whitespace, if you set the config by `Nacos UI` each subItemkey should in a new 
line:
+```
+subItemValue1
+subItemValue2
+...
+
+```
+If you set the config by `API` each subItemkey should separated by `\n` or 
`\r\n`:
+```
+configService.publishConfig("test-module.default.testKeyGroup", "skywalking", 
"subItemkey1\n subItemkey2"));
+```
+
+e.g. The config is:
+```
+{core.default.endpoint-name-grouping-openapi}:|{customerAPI-v1}:{value of 
customerAPI-v1}
+                                              |{productAPI-v1}:{value of 
productAPI-v1}
+                                              |{productAPI-v2}:{value of 
productAPI-v2}
+```
+If `group = skywalking` the config in nacos is:
+
+| Data Id | Group | Config Value | Config Type |
+|-----|-----|-----|-----|
+| core.default.endpoint-name-grouping-openapi | skywalking | 
customerAPI-v1</br>productAPI-v1</br>productAPI-v2 | TEXT |
+| customerAPI-v1 | skywalking | value of customerAPI-v1 |
+| productAPI-v1 | skywalking | value of productAPI-v1 |
+| productAPI-v2 | skywalking | value of productAPI-v2 |
+
+
diff --git 
a/oap-server/server-configuration/configuration-nacos/src/main/java/org/apache/skywalking/oap/server/configuration/nacos/NacosConfigWatcherRegister.java
 
b/oap-server/server-configuration/configuration-nacos/src/main/java/org/apache/skywalking/oap/server/configuration/nacos/NacosConfigWatcherRegister.java
index 47c741a..3a62040 100644
--- 
a/oap-server/server-configuration/configuration-nacos/src/main/java/org/apache/skywalking/oap/server/configuration/nacos/NacosConfigWatcherRegister.java
+++ 
b/oap-server/server-configuration/configuration-nacos/src/main/java/org/apache/skywalking/oap/server/configuration/nacos/NacosConfigWatcherRegister.java
@@ -23,6 +23,7 @@ import com.alibaba.nacos.api.PropertyKeyConst;
 import com.alibaba.nacos.api.config.ConfigService;
 import com.alibaba.nacos.api.config.listener.Listener;
 import com.alibaba.nacos.api.exception.NacosException;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Optional;
@@ -31,16 +32,14 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.apm.util.StringUtil;
 import org.apache.skywalking.oap.server.configuration.api.ConfigTable;
 import 
org.apache.skywalking.oap.server.configuration.api.ConfigWatcherRegister;
 import org.apache.skywalking.oap.server.configuration.api.GroupConfigTable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
+@Slf4j
 public class NacosConfigWatcherRegister extends ConfigWatcherRegister {
-    private static final Logger LOGGER = 
LoggerFactory.getLogger(NacosConfigWatcherRegister.class);
-
     private final NacosServerSettings settings;
     private final ConfigService configService;
     private final Map<String, Optional<String>> configItemKeyedByName;
@@ -92,8 +91,32 @@ public class NacosConfigWatcherRegister extends 
ConfigWatcherRegister {
 
     @Override
     public Optional<GroupConfigTable> readGroupConfig(final Set<String> keys) {
-        // TODO: implement readGroupConfig
-        return Optional.empty();
+        GroupConfigTable groupConfigTable = new GroupConfigTable();
+        keys.forEach(key -> {
+            GroupConfigTable.GroupConfigItems groupConfigItems = new 
GroupConfigTable.GroupConfigItems(key);
+            groupConfigTable.addGroupConfigItems(groupConfigItems);
+            String config = null;
+            try {
+                config = configService.getConfig(key, settings.getGroup(), 
1000);
+                if (StringUtil.isNotEmpty(config)) {
+                    String[] itemNames = config.split("\\n|\\r\\n");
+                    
Arrays.stream(itemNames).map(String::trim).forEach(itemName -> {
+                        String itemValue = null;
+                        try {
+                            itemValue = configService.getConfig(itemName, 
settings.getGroup(), 1000);
+                        } catch (NacosException e) {
+                            log.error("Failed to register Nacos listener for 
dataId: {}", itemName, e);
+                        }
+                        groupConfigItems.add(
+                            new ConfigTable.ConfigItem(itemName, itemValue));
+                    });
+                }
+            } catch (NacosException e) {
+                log.error("Failed to register Nacos listener for dataId: {}", 
key, e);
+            }
+        });
+
+        return Optional.of(groupConfigTable);
     }
 
     private void registerKeyListeners(final Set<String> keys) {
@@ -121,7 +144,7 @@ public class NacosConfigWatcherRegister extends 
ConfigWatcherRegister {
                 final String config = configService.getConfig(dataId, group, 
1000);
                 onDataIdValueChanged(dataId, config);
             } catch (NacosException e) {
-                LOGGER.warn("Failed to register Nacos listener for dataId: 
{}", dataId);
+                log.warn("Failed to register Nacos listener for dataId: {}", 
dataId);
             }
         }
     }
@@ -141,8 +164,8 @@ public class NacosConfigWatcherRegister extends 
ConfigWatcherRegister {
     }
 
     void onDataIdValueChanged(String dataId, String configInfo) {
-        if (LOGGER.isInfoEnabled()) {
-            LOGGER.info("Nacos config changed: {}: {}", dataId, configInfo);
+        if (log.isInfoEnabled()) {
+            log.info("Nacos config changed: {}: {}", dataId, configInfo);
         }
 
         configItemKeyedByName.put(dataId, Optional.ofNullable(configInfo));
diff --git 
a/oap-server/server-configuration/configuration-nacos/src/main/java/org/apache/skywalking/oap/server/configuration/nacos/NacosConfigurationProvider.java
 
b/oap-server/server-configuration/configuration-nacos/src/main/java/org/apache/skywalking/oap/server/configuration/nacos/NacosConfigurationProvider.java
index ad12683..1ab594b 100644
--- 
a/oap-server/server-configuration/configuration-nacos/src/main/java/org/apache/skywalking/oap/server/configuration/nacos/NacosConfigurationProvider.java
+++ 
b/oap-server/server-configuration/configuration-nacos/src/main/java/org/apache/skywalking/oap/server/configuration/nacos/NacosConfigurationProvider.java
@@ -20,20 +20,18 @@ package 
org.apache.skywalking.oap.server.configuration.nacos;
 
 import com.alibaba.nacos.api.exception.NacosException;
 import com.google.common.base.Strings;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.apm.util.StringUtil;
 import 
org.apache.skywalking.oap.server.configuration.api.AbstractConfigurationProvider;
 import 
org.apache.skywalking.oap.server.configuration.api.ConfigWatcherRegister;
 import org.apache.skywalking.oap.server.library.module.ModuleConfig;
 import org.apache.skywalking.oap.server.library.module.ModuleStartException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Get configuration from Nacos.
  */
+@Slf4j
 public class NacosConfigurationProvider extends AbstractConfigurationProvider {
-    private static final Logger LOGGER = 
LoggerFactory.getLogger(NacosConfigurationProvider.class);
-
     private NacosServerSettings settings;
 
     public NacosConfigurationProvider() {
@@ -52,7 +50,7 @@ public class NacosConfigurationProvider extends 
AbstractConfigurationProvider {
 
     @Override
     protected ConfigWatcherRegister initConfigReader() throws 
ModuleStartException {
-        LOGGER.info("settings: {}", settings);
+        log.info("settings: {}", settings);
         if (Strings.isNullOrEmpty(settings.getServerAddr())) {
             throw new ModuleStartException("Nacos serverAddr cannot be null or 
empty.");
         }
diff --git 
a/oap-server/server-configuration/configuration-nacos/src/test/java/org/apache/skywalking/oap/server/configuration/nacos/ITNacosConfigurationTest.java
 
b/oap-server/server-configuration/configuration-nacos/src/test/java/org/apache/skywalking/oap/server/configuration/nacos/ITNacosConfigurationTest.java
index d71d0ee..595cbe6 100644
--- 
a/oap-server/server-configuration/configuration-nacos/src/test/java/org/apache/skywalking/oap/server/configuration/nacos/ITNacosConfigurationTest.java
+++ 
b/oap-server/server-configuration/configuration-nacos/src/test/java/org/apache/skywalking/oap/server/configuration/nacos/ITNacosConfigurationTest.java
@@ -25,6 +25,7 @@ import java.io.FileNotFoundException;
 import java.io.Reader;
 import java.util.Map;
 import java.util.Properties;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.apm.util.PropertyPlaceholderHelper;
 import 
org.apache.skywalking.oap.server.library.module.ApplicationConfiguration;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
@@ -32,8 +33,6 @@ import 
org.apache.skywalking.oap.server.library.util.CollectionUtils;
 import org.apache.skywalking.oap.server.library.util.ResourceUtils;
 import org.junit.Before;
 import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.yaml.snakeyaml.Yaml;
 
 import static org.junit.Assert.assertEquals;
@@ -41,9 +40,8 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+@Slf4j
 public class ITNacosConfigurationTest {
-    private static final Logger LOGGER = 
LoggerFactory.getLogger(ITNacosConfigurationTest.class);
-
     private final Yaml yaml = new Yaml();
 
     private NacosConfigurationTestProvider provider;
@@ -69,7 +67,7 @@ public class ITNacosConfigurationTest {
         final Properties properties = new Properties();
         final String nacosHost = System.getProperty("nacos.host");
         final String nacosPort = System.getProperty("nacos.port");
-        LOGGER.info("nacosHost: {}, nacosPort: {}", nacosHost, nacosPort);
+        log.info("nacosHost: {}, nacosPort: {}", nacosHost, nacosPort);
         properties.put("serverAddr", nacosHost + ":" + nacosPort);
 
         final ConfigService configService = 
NacosFactory.createConfigService(properties);
@@ -88,6 +86,50 @@ public class ITNacosConfigurationTest {
         assertNull(provider.watcher.value());
     }
 
+    @Test(timeout = 20000)
+    public void shouldReadUpdatedGroup() throws NacosException {
+        assertNull(provider.watcher.value());
+
+        final Properties properties = new Properties();
+        final String nacosHost = System.getProperty("nacos.host");
+        final String nacosPort = System.getProperty("nacos.port");
+        log.info("nacosHost: {}, nacosPort: {}", nacosHost, nacosPort);
+        properties.put("serverAddr", nacosHost + ":" + nacosPort);
+
+        final ConfigService configService = 
NacosFactory.createConfigService(properties);
+        //test add group key and item1 item2
+        
assertTrue(configService.publishConfig("test-module.default.testKeyGroup", 
"skywalking", "item1\n item2"));
+        assertTrue(configService.publishConfig("item1", "skywalking", "100"));
+        assertTrue(configService.publishConfig("item2", "skywalking", "200"));
+        for (String v = provider.groupWatcher.groupItems().get("item1"); v == 
null; v = provider.groupWatcher.groupItems().get("item1")) {
+        }
+        for (String v = provider.groupWatcher.groupItems().get("item2"); v == 
null; v = provider.groupWatcher.groupItems().get("item2")) {
+        }
+        assertEquals("100", provider.groupWatcher.groupItems().get("item1"));
+        assertEquals("200", provider.groupWatcher.groupItems().get("item2"));
+
+        //test remove item1
+        assertTrue(configService.removeConfig("item1", "skywalking"));
+        for (String v = provider.groupWatcher.groupItems().get("item1"); v != 
null; v = provider.groupWatcher.groupItems().get("item1")) {
+        }
+        assertNull(provider.groupWatcher.groupItems().get("item1"));
+
+        //test modify item1
+        assertTrue(configService.publishConfig("item1", "skywalking", "300"));
+        for (String v = provider.groupWatcher.groupItems().get("item1"); v == 
null; v = provider.groupWatcher.groupItems().get("item1")) {
+        }
+        assertEquals("300", provider.groupWatcher.groupItems().get("item1"));
+
+        //test remove group key
+        
assertTrue(configService.removeConfig("test-module.default.testKeyGroup", 
"skywalking"));
+        for (String v = provider.groupWatcher.groupItems().get("item2"); v != 
null; v = provider.groupWatcher.groupItems().get("item2")) {
+        }
+        assertNull(provider.groupWatcher.groupItems().get("item2"));
+        //chean
+        assertTrue(configService.removeConfig("item1", "skywalking"));
+        assertTrue(configService.removeConfig("item2", "skywalking"));
+    }
+
     @SuppressWarnings("unchecked")
     private void loadConfig(ApplicationConfiguration configuration) throws 
FileNotFoundException {
         Reader applicationReader = ResourceUtils.read("application.yml");
diff --git 
a/oap-server/server-configuration/configuration-nacos/src/test/java/org/apache/skywalking/oap/server/configuration/nacos/NacosConfigurationTestProvider.java
 
b/oap-server/server-configuration/configuration-nacos/src/test/java/org/apache/skywalking/oap/server/configuration/nacos/NacosConfigurationTestProvider.java
index ff2d097..fee0826 100644
--- 
a/oap-server/server-configuration/configuration-nacos/src/test/java/org/apache/skywalking/oap/server/configuration/nacos/NacosConfigurationTestProvider.java
+++ 
b/oap-server/server-configuration/configuration-nacos/src/test/java/org/apache/skywalking/oap/server/configuration/nacos/NacosConfigurationTestProvider.java
@@ -18,21 +18,23 @@
 
 package org.apache.skywalking.oap.server.configuration.nacos;
 
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.oap.server.configuration.api.ConfigChangeWatcher;
 import org.apache.skywalking.oap.server.configuration.api.ConfigurationModule;
 import 
org.apache.skywalking.oap.server.configuration.api.DynamicConfigurationService;
+import 
org.apache.skywalking.oap.server.configuration.api.GroupConfigChangeWatcher;
 import org.apache.skywalking.oap.server.library.module.ModuleConfig;
 import org.apache.skywalking.oap.server.library.module.ModuleDefine;
 import org.apache.skywalking.oap.server.library.module.ModuleProvider;
 import org.apache.skywalking.oap.server.library.module.ModuleStartException;
 import 
org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
+@Slf4j
 public class NacosConfigurationTestProvider extends ModuleProvider {
-    private static final Logger LOGGER = 
LoggerFactory.getLogger(NacosConfigurationTestProvider.class);
-
     ConfigChangeWatcher watcher;
+    GroupConfigChangeWatcher groupWatcher;
 
     @Override
     public String name() {
@@ -57,7 +59,7 @@ public class NacosConfigurationTestProvider extends 
ModuleProvider {
 
             @Override
             public void notify(ConfigChangeEvent value) {
-                LOGGER.info("ConfigChangeWatcher.ConfigChangeEvent: {}", 
value);
+                log.info("ConfigChangeWatcher.ConfigChangeEvent: {}", value);
                 if (EventType.DELETE.equals(value.getEventType())) {
                     testValue = null;
                 } else {
@@ -70,6 +72,27 @@ public class NacosConfigurationTestProvider extends 
ModuleProvider {
                 return testValue;
             }
         };
+
+        groupWatcher = new 
GroupConfigChangeWatcher(NacosConfigurationTestModule.NAME, this, 
"testKeyGroup") {
+            private Map<String, String> config = new ConcurrentHashMap<>();
+
+            @Override
+            public void notifyGroup(Map<String, ConfigChangeEvent> groupItems) 
{
+                log.info("GroupConfigChangeWatcher.ConfigChangeEvents: {}", 
groupItems);
+                groupItems.forEach((groupItemName, event) -> {
+                    if (EventType.DELETE.equals(event.getEventType())) {
+                        config.remove(groupItemName);
+                    } else {
+                        config.put(groupItemName, event.getNewValue());
+                    }
+                });
+            }
+
+            @Override
+            public Map<String, String> groupItems() {
+                return config;
+            }
+        };
     }
 
     @Override
@@ -78,6 +101,11 @@ public class NacosConfigurationTestProvider extends 
ModuleProvider {
                     .provider()
                     .getService(DynamicConfigurationService.class)
                     .registerConfigChangeWatcher(watcher);
+
+        getManager().find(ConfigurationModule.NAME)
+                    .provider()
+                    .getService(DynamicConfigurationService.class)
+                    .registerConfigChangeWatcher(groupWatcher);
     }
 
     @Override

Reply via email to