feature: add client labels collect and attach labels to conn (#11844)

* add client labels collect and attach labels to conn

* remove some constants

* fixup test case
This commit is contained in:
brother-戎 2024-03-21 14:33:57 +08:00 committed by GitHub
parent b79d585f97
commit 9fd6ff6a04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 1256 additions and 3 deletions

View File

@ -33,6 +33,8 @@ public class Constants {
public static final String APPNAME = "AppName";
public static final String CLIENT_VERSION_KEY = "ClientVersion";
public static final String UNKNOWN_APP = "UnknownApp";
public static final String DEFAULT_DOMAINNAME = "commonconfig.config-host.taobao.com";
@ -223,6 +225,36 @@ public class Constants {
public static final int DEFAULT_REDO_THREAD_COUNT = 1;
public static final String APP_CONN_LABELS_PREFIX = "nacos.app.conn.labels";
public static final String GRAY = "gray";
public static final String DOT = ".";
public static final String WEIGHT = "weight";
public static final String PROPERTIES_KEY = "properties";
public static final String JVM_KEY = "jvm";
public static final String ENV_KEY = "env";
public static final String APP_CONN_LABELS_PROPERTIES_WEIGHT_KEY = APP_CONN_LABELS_PREFIX + DOT + WEIGHT + DOT + PROPERTIES_KEY;
public static final int APP_CONN_LABELS_PROPERTIES_DEFAULT_WEIGHT = 3;
public static final String APP_CONN_LABELS_JVM_WEIGHT_KEY = APP_CONN_LABELS_PREFIX + DOT + WEIGHT + DOT + JVM_KEY;
public static final int APP_CONN_LABELS_JVM_DEFAULT_WEIGHT = 2;
public static final String APP_CONN_LABELS_ENV_WEIGHT_KEY = APP_CONN_LABELS_PREFIX + DOT + WEIGHT + DOT + ENV_KEY;
public static final int APP_CONN_LABELS_ENV_DEFAULT_WEIGHT = 1;
public static final String APP_CONN_PREFIX = "app_";
public static final String CONFIG_GRAY = "nacos.config" + DOT + GRAY;
/**
* The constants in config directory.
*/

View File

@ -1071,7 +1071,7 @@ public class ClientWorker implements Closeable {
Map<String, String> newLabels = new HashMap<>(labels);
newLabels.put("taskId", taskId);
RpcClient rpcClient = RpcClientFactory.createClient(uuid + "_config-" + taskId, getConnectionType(),
newLabels, RpcClientTlsConfig.properties(this.properties));
newLabels, this.properties, RpcClientTlsConfig.properties(this.properties));
if (rpcClient.isWaitInitiated()) {
initRpcClientHandler(rpcClient);
rpcClient.setTenant(getTenant());

View File

@ -99,6 +99,9 @@ public class ClientWorkerTest {
rpcClientFactoryMockedStatic.when(
() -> RpcClientFactory.createClient(anyString(), any(ConnectionType.class), any(Map.class),
any(RpcClientTlsConfig.class))).thenReturn(rpcClient);
rpcClientFactoryMockedStatic.when(
() -> RpcClientFactory.createClient(anyString(), any(ConnectionType.class), any(Map.class),
any(Properties.class), any(RpcClientTlsConfig.class))).thenReturn(rpcClient);
localConfigInfoProcessorMockedStatic = Mockito.mockStatic(LocalConfigInfoProcessor.class);
Properties properties = new Properties();
properties.put(PropertyKeyConst.NAMESPACE, TEST_NAMESPACE);
@ -555,7 +558,7 @@ public class ClientWorkerTest {
Mockito.when(rpcClientInner.isWaitInitiated()).thenReturn(true, false);
rpcClientFactoryMockedStatic.when(
() -> RpcClientFactory.createClient(anyString(), any(ConnectionType.class), any(Map.class),
any(RpcClientTlsConfig.class))).thenReturn(rpcClientInner);
any(Properties.class), any(RpcClientTlsConfig.class))).thenReturn(rpcClientInner);
// mock listen and remove listen request
Mockito.when(rpcClientInner.request(any(ConfigBatchListenRequest.class), anyLong()))
.thenReturn(response, response);

View File

@ -0,0 +1,66 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels;
import java.util.Map;
import java.util.Properties;
/**
* LabelsCollector.
*
* @author rong
* @date 2024/2/4
*/
public interface LabelsCollector {
/**
* init labels.
*
* @param properties Properties
* @date 2024/2/4
* @description init labels
*/
void init(Properties properties);
/**
* getLabels.
*
* @return Map
* @date 2024/2/4
* @description get all labels
*/
Map<String, String> getLabels();
/**
* getOrder.
*
* @return the order value
* @date 2024/2/4
* @description get order value of labels in case of multiple labels
*/
int getOrder();
/**
* get collector name.
*
* @return name of collector
* @date 2024/2/4
* @description name of collector
*/
String getName();
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels;
import java.util.Map;
import java.util.Properties;
/**
* LabelsCollectorManager.
*
* @author rong
* @date 2024/2/4
*/
public interface LabelsCollectorManager {
/**
* get all labels collected.
*
* @date 2024/2/4
* @description
* @return all labels
*/
Map<String, String> getAllLabels();
/**
* refresh all labels.
*
* @date 2024/3/7
* @param properties Properties.
* @return all labels.
*/
Map<String, String> refreshAllLabels(Properties properties);
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels.impl;
import com.alibaba.nacos.common.labels.LabelsCollector;
import java.util.HashMap;
import java.util.Map;
/**
* AbstractLabelsCollector.
*
* @author rong
*/
public abstract class AbstractLabelsCollector implements LabelsCollector {
protected Map<String, String> labels = new HashMap<>(2);
private static final int DEFAULT_INITIAL_ORDER = 100;
@Override
public Map<String, String> getLabels() {
return labels;
}
@Override
public int getOrder() {
return DEFAULT_INITIAL_ORDER;
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels.impl;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.common.labels.LabelsCollector;
import com.alibaba.nacos.common.labels.impl.utils.ConfigGetterManager;
import com.alibaba.nacos.common.utils.ConnLabelsUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Properties;
/**
* DefaultLabelsCollector.
*
* @author rong
*/
public class DefaultLabelsCollector extends AbstractLabelsCollector implements LabelsCollector {
protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultLabelsCollector.class);
private final String customName = "defaultLabelsCollector";
/**
* init labels.
*
* @date 2024/2/4
*@description will init from properties, JVM OPTIONS, ENV by order of <tt>properties > JVM OPTIONS > ENV</tt> by default.
* which will use the next level value when the current level value isn't setup (you also can set the level by env).
* <p>eg: if the value of "nacos.app.conn.labels"(properties' key) is "k1=v1,k2=v2"(properties' value), the result will be
* a Map with value{k1=v1,k2=v2}.</p>
* @param properties Properties
*/
@Override
public void init(Properties properties) {
ConfigGetterManager configGetterManager = new ConfigGetterManager(properties);
labels.putAll(ConnLabelsUtils.parseRawLabels(configGetterManager.getConfig(Constants.APP_CONN_LABELS_PREFIX)));
String grayLabelValue = configGetterManager.getConfig(Constants.CONFIG_GRAY);
if (StringUtils.isNotBlank(grayLabelValue)) {
labels.put(Constants.GRAY, grayLabelValue);
}
for (Map.Entry<String, String> entry : labels.entrySet()) {
LOGGER.info("init labels: {}={}", entry.getKey(), entry.getValue());
}
}
@Override
public String getName() {
return customName;
}
}

View File

@ -0,0 +1,141 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels.impl;
import com.alibaba.nacos.common.labels.LabelsCollector;
import com.alibaba.nacos.common.labels.LabelsCollectorManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
/**
* DefaultLabelsCollectorManager.
*
* @author rong
*/
public class DefaultLabelsCollectorManager implements LabelsCollectorManager {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultLabelsCollectorManager.class);
private ArrayList<LabelsCollector> labelsCollectorsList = new ArrayList<>();
private Map<String, String> labels = new HashMap<>();
private static final int MAX_TRY_COUNT = 3;
private volatile boolean isLabelsInit = false;
public DefaultLabelsCollectorManager(Properties properties) {
init(properties);
}
private void init(Properties properties) {
if (isLabelsInit) {
return;
}
synchronized (this) {
if (isLabelsInit) {
return;
}
isLabelsInit = true;
LOGGER.info("DefaultLabelsCollectorManager init labels.....");
initLabels(properties);
LOGGER.info("DefaultLabelsCollectorManager init labels finished, labels:{}", labels);
}
}
public Map<String, String> getAllLabels() {
for (int tryTimes = 0; tryTimes < MAX_TRY_COUNT && !isLabelsInit; tryTimes++) {
try {
Thread.sleep(100);
} catch (Exception e) {
//do nothing
}
}
return labels;
}
@Override
public Map<String, String> refreshAllLabels(Properties properties) {
for (int tryTimes = 0; tryTimes < MAX_TRY_COUNT && !isLabelsInit; tryTimes++) {
try {
Thread.sleep(100);
} catch (Exception e) {
//do nothing
}
}
if (!isLabelsInit) {
return new HashMap<>(2);
}
LOGGER.info("DefaultLabelsCollectorManager refresh labels.....");
initLabels(properties);
LOGGER.info("DefaultLabelsCollectorManager refresh labels finished,labels :{}", labels);
return labels;
}
private ArrayList<LabelsCollector> loadLabelsCollectors() {
ServiceLoader<LabelsCollector> labelsCollectors = ServiceLoader.load(LabelsCollector.class);
ArrayList<LabelsCollector> labelsCollectorsList = new ArrayList<>();
for (LabelsCollector labelsCollector : labelsCollectors) {
labelsCollectorsList.add(labelsCollector);
}
labelsCollectorsList.sort((o1, o2) -> o2.getOrder() - o1.getOrder());
return labelsCollectorsList;
}
private void initLabels(Properties properties) {
labelsCollectorsList = loadLabelsCollectors();
this.labels = getLabels(labelsCollectorsList, properties);
}
Map<String, String> getLabels(ArrayList<LabelsCollector> labelsCollectorsList, Properties properties) {
Map<String, String> labels = new HashMap<>(8);
for (LabelsCollector labelsCollector : labelsCollectorsList) {
try {
LOGGER.info("LabelsCollector with name [{}] initializing......", labelsCollector.getName());
labelsCollector.init(properties);
LOGGER.info("LabelsCollector with name [{}] initialize finished......", labelsCollector.getName());
} catch (Exception e) {
LOGGER.error("init LabelsCollector with [name:{}] failed", labelsCollector.getName(), e);
continue;
}
LOGGER.info("Process LabelsCollector with [name:{}]", labelsCollector.getName());
for (Map.Entry<String, String> entry : labelsCollector.getLabels().entrySet()) {
if (innerAddLabel(labels, entry.getKey(), entry.getValue())) {
LOGGER.info("pick label with [key:{}, value:{}] of collector [name:{}]", entry.getKey(),
entry.getValue(), labelsCollector.getName());
} else {
LOGGER.info(
" ignore label with [key:{}, value:{}] of collector [name:{}],"
+ "already existed in LabelsCollectorManager with previous [value:{}]",
entry.getKey(), entry.getValue(), labelsCollector.getName(), labels.get(entry.getKey()));
}
}
}
return labels;
}
private boolean innerAddLabel(Map<String, String> labels, String key, String value) {
return null == labels.putIfAbsent(key, value);
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels.impl.utils;
import com.alibaba.nacos.common.utils.StringUtils;
import org.slf4j.Logger;
import java.util.Properties;
/**
* AbstractConfigGetter.
*
* @author rong
* @date 2024-03-06 17:42
*/
public abstract class AbstractConfigGetter implements OrderedConfigGetter {
protected Logger logger;
protected int order;
@Override
public void init(Properties properties) {
String weightKey = getWeightKey();
String weight = properties.getProperty(weightKey, System.getProperty(weightKey, System.getenv(weightKey)));
if (StringUtils.isBlank(weight)) {
return;
}
try {
order = Integer.parseInt(weight);
} catch (NumberFormatException e) {
logger.error("parse weight error, weight={}", weight, e);
}
}
/**
* get weight key which will be used to get weight from properties/env/jvm.
*
* @date 2024/3/7
* @return String weight key.
*/
protected abstract String getWeightKey();
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels.impl.utils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
/**
* description.
*
* @author rong
* @date 2024-03-07 10:02
*/
public class ConfigGetterManager {
private final List<OrderedConfigGetter> priorityList = new ArrayList<>();
public String getConfig(String key) {
for (OrderedConfigGetter getter : priorityList) {
String config = getter.getConfig(key);
if (config != null) {
return config;
}
}
return null;
}
public ConfigGetterManager(Properties properties) {
Properties temp = new Properties();
temp.putAll(properties);
init(temp);
}
private void init(Properties properties) {
priorityList.add(new PropertiesConfigGetter());
priorityList.add(new JvmConfigGetter());
priorityList.add(new EnvConfigGetter());
priorityList.stream().filter(Objects::nonNull).forEach(getter -> getter.init(properties));
priorityList.sort((o1, o2) -> o2.order() - o1.order());
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels.impl.utils;
import com.alibaba.nacos.api.common.Constants;
import org.slf4j.LoggerFactory;
import java.util.Properties;
/**
* EnvConfigGetter.
*
* @author rong
* @date 2024-03-06 17:42
*/
public class EnvConfigGetter extends AbstractConfigGetter implements OrderedConfigGetter {
@Override
public void init(Properties properties) {
order = Constants.APP_CONN_LABELS_ENV_DEFAULT_WEIGHT;
logger = LoggerFactory.getLogger(EnvConfigGetter.class);
super.init(properties);
}
@Override
protected String getWeightKey() {
return Constants.APP_CONN_LABELS_ENV_WEIGHT_KEY;
}
@Override
public int order() {
return order;
}
@Override
public String getConfig(String key) {
return System.getenv(key);
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels.impl.utils;
import com.alibaba.nacos.api.common.Constants;
import org.slf4j.LoggerFactory;
import java.util.Properties;
/**
* JvmConfigGetter.
*
* @author rong
* @date 2024-03-06 17:42
*/
public class JvmConfigGetter extends AbstractConfigGetter implements OrderedConfigGetter {
@Override
public void init(Properties properties) {
order = Constants.APP_CONN_LABELS_JVM_DEFAULT_WEIGHT;
logger = LoggerFactory.getLogger(JvmConfigGetter.class);
super.init(properties);
}
@Override
protected String getWeightKey() {
return Constants.APP_CONN_LABELS_JVM_WEIGHT_KEY;
}
@Override
public int order() {
return order;
}
@Override
public String getConfig(String key) {
return System.getProperty(key);
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels.impl.utils;
import java.util.Properties;
/**
* OrderedConfigGetter.
*
* @author rong
*/
public interface OrderedConfigGetter {
/**
* init.
*
* @date 2024/3/6
* @param properties properties.
*/
void init(Properties properties);
/**
* get order.
*
* @date 2024/3/6
* @return the order.
*/
int order();
/**
* get config by key.
*
* @date 2024/3/6
* @param key key.
* @return the config.
*/
String getConfig(String key);
}

View File

@ -0,0 +1,60 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels.impl.utils;
import com.alibaba.nacos.api.common.Constants;
import org.slf4j.LoggerFactory;
import java.util.Properties;
/**
* PropertiesConfigGetter.
*
* @author rong
* @date 2024-03-06 17:42
*/
public class PropertiesConfigGetter extends AbstractConfigGetter implements OrderedConfigGetter {
private Properties properties;
@Override
public void init(Properties properties) {
this.properties = properties;
order = Constants.APP_CONN_LABELS_PROPERTIES_DEFAULT_WEIGHT;
logger = LoggerFactory.getLogger(PropertiesConfigGetter.class);
super.init(properties);
}
@Override
protected String getWeightKey() {
return Constants.APP_CONN_LABELS_PROPERTIES_WEIGHT_KEY;
}
@Override
public int order() {
return order;
}
@Override
public String getConfig(String key) {
if (properties == null) {
return null;
}
return properties.getProperty(key);
}
}

View File

@ -17,15 +17,21 @@
package com.alibaba.nacos.common.remote.client;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.labels.impl.DefaultLabelsCollectorManager;
import com.alibaba.nacos.common.remote.ConnectionType;
import com.alibaba.nacos.common.remote.client.grpc.GrpcClusterClient;
import com.alibaba.nacos.common.remote.client.grpc.GrpcSdkClient;
import com.alibaba.nacos.common.utils.ConnLabelsUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import static com.alibaba.nacos.api.common.Constants.APP_CONN_PREFIX;
/**
* RpcClientFactory.to support multi client for different modules of usage.
@ -39,6 +45,8 @@ public class RpcClientFactory {
private static final Map<String, RpcClient> CLIENT_MAP = new ConcurrentHashMap<>();
private static AtomicReference<DefaultLabelsCollectorManager> defaultLabelsCollectorManager;
/**
* get all client.
*
@ -78,7 +86,22 @@ public class RpcClientFactory {
public static RpcClient createClient(String clientName, ConnectionType connectionType, Map<String, String> labels,
RpcClientTlsConfig tlsConfig) {
return createClient(clientName, connectionType, null, null, labels, tlsConfig);
}
/**
* create client with properties.
*
* @date 2024/3/7
* @return rpc client.
*/
public static RpcClient createClient(String clientName, ConnectionType connectionType, Map<String, String> labels,
Properties properties, RpcClientTlsConfig tlsConfig) {
try {
labels = ConnLabelsUtils.mergeMapByOrder(labels, collectLabels(properties));
} catch (Exception e) {
LOGGER.error("Collect labels error when creating config rpc client", e);
}
return createClient(clientName, connectionType, null, null, labels, tlsConfig);
}
public static RpcClient createClient(String clientName, ConnectionType connectionType, Integer threadPoolCoreSize,
@ -109,6 +132,22 @@ public class RpcClientFactory {
});
}
/**
* collect labels.
*
* @return the labels map
* @description will get labels map from properties, valueFromSpi, JVM OPTIONS or ENV by order of properties >
* valueFromSpi > JVM OPTIONS > ENV which will use the next level value when the key doesn't exist in current
* map
*/
private static Map<String, String> collectLabels(Properties properties) {
//labels from spi
defaultLabelsCollectorManager.compareAndSet(null, new DefaultLabelsCollectorManager(properties));
Map<String, String> allLabels = defaultLabelsCollectorManager.get().refreshAllLabels(properties);
allLabels = ConnLabelsUtils.addPrefixForEachKey(allLabels, APP_CONN_PREFIX);
return allLabels;
}
/**
* create a rpc client.
*

View File

@ -0,0 +1,144 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.stream.Collectors;
/**
* ConnLabelsUtils.
*
* @author rong
*/
public class ConnLabelsUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(ConnLabelsUtils.class);
public static final String LABEL_EQUALS_OPERATOR = "=";
public static final String LABEL_SPLIT_OPERATOR = ",";
public static final int TAG_V2_LABEL_KEY_VALUE_SPLIT_LENGTH = 2;
public static final int TAG_V1_LABEL_KEY_VALUE_SPLIT_LENGTH = 1;
/**
* parse property value to map.
*
* @date 2024/1/29
* @description will get a key-value map from properties, JVM OPTIONS, ENV by order of <tt>properties > JVM OPTIONS > ENV</tt>
* which will use the next level value when the current level value isn't setup.
* <p>eg: if the value of "nacos.app.conn.labels"(properties' key) is "k1=v1,k2=v2"(properties' value), the result will be
* a Map with value{k1=v1,k2=v2}.</p>
* @param properties Properties
* @param propertyName which key to get
* @return (String)key-(String)value map
*/
public static Map<String, String> parsePropertyValue2Map(Properties properties, String propertyName) {
String rawLabels = properties.getProperty(propertyName, System.getProperty(propertyName, System.getenv(propertyName)));
if (StringUtils.isBlank(rawLabels)) {
LOGGER.info("no value found for property key: {}", propertyName);
return new HashMap<>(2);
}
return parseRawLabels(rawLabels);
}
/**
* parse raw json labels into a key-value map.
*
* @date 2024/1/29
* @description
* @param rawLabels rawLabels to parse
* @return map parsed from rawLabels
*/
public static Map<String, String> parseRawLabels(String rawLabels) {
if (StringUtils.isBlank(rawLabels)) {
return new HashMap<>(2);
}
HashMap<String, String> resultMap = new HashMap<>(2);
try {
Arrays.stream(rawLabels.split(LABEL_SPLIT_OPERATOR))
.filter(Objects::nonNull)
.map(String::trim)
.filter(StringUtils::isNotBlank)
.forEach(label -> {
String[] kv = label.split(LABEL_EQUALS_OPERATOR);
if (kv.length == TAG_V2_LABEL_KEY_VALUE_SPLIT_LENGTH) {
resultMap.put(kv[0].trim(), kv[1].trim());
} else if (kv.length == TAG_V1_LABEL_KEY_VALUE_SPLIT_LENGTH) {
resultMap.put(kv[0].trim(), kv[0].trim());
} else {
LOGGER.error("unknown label format: {}", label);
}
});
} catch (Exception e) {
LOGGER.error("unknown label format: {}", rawLabels);
}
return resultMap;
}
/**
* merge two map into one by using the former value when key is duplicated.
*
* @date 2024/1/29
* @description merge two map into one preferring using the first one when key is duplicated
* @param preferredMap preferredMap
* @param backwardMap backwardMap
*/
public static <T, R> Map<T, R> mergeMapByOrder(Map<T, R> preferredMap, Map<T, R> backwardMap) {
if (preferredMap == null || preferredMap.isEmpty()) {
return new HashMap<T, R>(8) { {
putAll(backwardMap); } };
}
if (backwardMap == null || backwardMap.isEmpty()) {
return new HashMap<T, R>(8) { {
putAll(preferredMap); } };
}
HashMap<T, R> resultMap = new HashMap<T, R>(8) {{
putAll(preferredMap); } };
backwardMap.forEach((key, value) -> {
if (!resultMap.containsKey(key)) {
resultMap.put(key, value);
}
});
return resultMap;
}
/**
* add prefix for each key in map.
*
* @date 2024/1/29
* @description add prefix for each key in map
* @param map map to add prefix
* @param prefix prefix
*/
public static <T> Map<String, T> addPrefixForEachKey(Map<String, T> map, String prefix) {
if (map == null || map.isEmpty()) {
return map;
}
return map.entrySet().stream().filter(Objects::nonNull)
.filter(elem -> !elem.getKey().trim().isEmpty())
.collect(Collectors.toMap(elem -> prefix + elem.getKey(), Map.Entry::getValue));
}
}

View File

@ -0,0 +1,19 @@
#
#
# Copyright 1999-2023 Alibaba Group Holding Ltd.
#
# Licensed 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.
#
#
com.alibaba.nacos.common.labels.impl.DefaultLabelsCollector

View File

@ -0,0 +1,57 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels.impl;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.common.labels.impl.utils.ConfigGetterManager;
import org.junit.Assert;
import org.junit.Test;
import java.util.Properties;
/**
* description.
*
* @author rong
* @date 2024-03-07 11:10
*/
public class ConfigGetterManagerTest {
@Test
public void testGetByOrder() {
Properties init = new Properties();
init.put(Constants.APP_CONN_LABELS_PROPERTIES_WEIGHT_KEY, "1");
init.put(Constants.APP_CONN_LABELS_ENV_WEIGHT_KEY, "2");
init.put(Constants.APP_CONN_LABELS_JVM_WEIGHT_KEY, "3");
System.setProperty(Constants.APP_CONN_LABELS_PREFIX, "gray=jvm_pre");
init.put(Constants.APP_CONN_LABELS_PREFIX, "gray=properties_pre");
String result = new ConfigGetterManager(init).getConfig(Constants.APP_CONN_LABELS_PREFIX);
Assert.assertEquals("gray=jvm_pre", result);
init.put(Constants.APP_CONN_LABELS_PROPERTIES_WEIGHT_KEY, "3");
init.put(Constants.APP_CONN_LABELS_ENV_WEIGHT_KEY, "2");
init.put(Constants.APP_CONN_LABELS_JVM_WEIGHT_KEY, "1");
result = new ConfigGetterManager(init).getConfig(Constants.APP_CONN_LABELS_PREFIX);
Assert.assertEquals("gray=properties_pre", result);
init.remove(Constants.APP_CONN_LABELS_PREFIX);
result = new ConfigGetterManager(init).getConfig(Constants.APP_CONN_LABELS_PREFIX);
Assert.assertEquals("gray=jvm_pre", result);
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 1999-2023 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels.impl;
import com.alibaba.nacos.api.common.Constants;
import org.junit.Assert;
import org.junit.Test;
import java.util.Map;
import java.util.Properties;
/**
* description.
*
* @author rong
* @date 2024-02-29 20:13
*/
public class DefaultLabelsCollectorManagerTest {
@Test
public void tagV2LabelsCollectorTest() {
Properties properties = new Properties();
properties.put(Constants.APP_CONN_LABELS_PREFIX, "k1=v1,gray=properties_pre");
properties.put(Constants.CONFIG_GRAY, "properties_after");
DefaultLabelsCollectorManager defaultLabelsCollectorManager = new DefaultLabelsCollectorManager(properties);
Map<String, String> labels = defaultLabelsCollectorManager.getAllLabels();
Assert.assertEquals("properties_after", labels.get(Constants.GRAY));
Assert.assertEquals("v1", labels.get("k1"));
}
@Test
public void tagV2LabelsCollectorOrderTest() {
Properties properties = new Properties();
DefaultLabelsCollectorManager defaultLabelsCollectorManager = new DefaultLabelsCollectorManager(properties);
Map<String, String> labels = defaultLabelsCollectorManager.getAllLabels();
String test = labels.get("test");
Assert.assertEquals("test2", test);
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels.impl;
import com.alibaba.nacos.common.labels.LabelsCollector;
import java.util.Properties;
/**
* Test1LabelsCollector.
*
* @author rong
*/
public class Test1LabelsCollector extends AbstractLabelsCollector implements LabelsCollector {
@Override
public String getName() {
return "test1";
}
@Override
public void init(Properties properties) {
labels.put("test", getName());
}
@Override
public int getOrder() {
return 1;
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.labels.impl;
import com.alibaba.nacos.common.labels.LabelsCollector;
import java.util.Properties;
/**
* TagV1LabelsCollector.
*
* @author rong
*/
public class Test2LabelsCollector extends AbstractLabelsCollector implements LabelsCollector {
@Override
public String getName() {
return "test2";
}
@Override
public void init(Properties properties) {
labels.put("test", getName());
}
@Override
public int getOrder() {
return 2;
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed 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 com.alibaba.nacos.common.utils;
import org.junit.Test;
import java.util.Map;
import java.util.Properties;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* description.
*
* @author rong
* @date 2024-03-01 15:10
*/
public class ConnLabelsUtilsTest {
@Test
public void testParsePropertyValue2Map() {
Properties properties = new Properties();
String property = "property";
String rawValue = "k1 = v1, k2 = v2";
properties.put(property, rawValue);
String property1 = "property2";
String rawValue1 = "k1, kk2";
properties.put(property1, rawValue1);
Map<String, String> m = ConnLabelsUtils.parsePropertyValue2Map(properties, property);
assertEquals(2, m.size());
assertEquals("v1", m.get("k1"));
assertEquals("v2", m.get("k2"));
Map<String, String> m1 = ConnLabelsUtils.parsePropertyValue2Map(properties, property1);
assertEquals(2, m.size());
assertEquals("k1", m1.get("k1"));
assertEquals("kk2", m1.get("kk2"));
m = ConnLabelsUtils.mergeMapByOrder(m, m1);
assertEquals(3, m.size());
assertEquals("v1", m.get("k1"));
assertEquals("v2", m.get("k2"));
assertEquals("kk2", m.get("kk2"));
m = ConnLabelsUtils.addPrefixForEachKey(m, "test_prefix");
assertEquals(3, m.size());
m.forEach((k, v) -> {
assertTrue(k.startsWith("test_prefix"));
});
}
}

View File

@ -0,0 +1,21 @@
#
#
# Copyright 1999-2023 Alibaba Group Holding Ltd.
#
# Licensed 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.
#
#
com.alibaba.nacos.common.labels.impl.DefaultLabelsCollector
com.alibaba.nacos.common.labels.impl.Test1LabelsCollector
com.alibaba.nacos.common.labels.impl.Test2LabelsCollector

View File

@ -43,6 +43,10 @@ public abstract class Connection implements Requester {
return metaInfo.getLabels();
}
public Map<String, String> getAppLabels() {
return metaInfo.getAppLabels();
}
public boolean isTraced() {
return traced;
}

View File

@ -16,11 +16,16 @@
package com.alibaba.nacos.core.remote;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.remote.RemoteConstants;
import com.alibaba.nacos.common.utils.ConnLabelsUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static com.alibaba.nacos.api.common.Constants.VIPSERVER_TAG;
@ -145,6 +150,26 @@ public class ConnectionMeta {
return labels;
}
/**
* get labels map with filter of starting with prefix #{@link Constants#APP_CONN_PREFIX}
* and return a new map trim the prefix #{@link Constants#APP_CONN_PREFIX}.
* @date 2024/2/29
* @return map of labels.
*/
public Map<String, String> getAppLabels() {
HashMap<String, String> labelsMap = new HashMap<String, String>(8) {
{
put(Constants.APPNAME, labels.get(Constants.APPNAME));
put(Constants.CLIENT_VERSION_KEY, version);
}
};
return ConnLabelsUtils.mergeMapByOrder(labelsMap, labels.entrySet().stream().filter(Objects::nonNull)
.filter(e -> e.getKey().startsWith(Constants.APP_CONN_PREFIX)
&& e.getKey().length() > Constants.APP_CONN_PREFIX.length()
&& StringUtils.isNotBlank(e.getValue())).collect(
Collectors.toMap(k -> k.getKey().substring(Constants.APP_CONN_PREFIX.length()), Map.Entry::getValue)));
}
/**
* Setter method for property <tt>labels</tt>.
*