fix: tsf related bugfixes (#1682)

pull/1684/head
Fishtail 1 month ago committed by GitHub
parent 8a2c061e5d
commit f2a1cef179
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -16,7 +16,7 @@ header:
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
paths:
- "**/tencent/**"
- "**/*.java"
language:
Java:
extensions:

@ -8,3 +8,4 @@
- [fix: fix ConfigChangeListener and unit test](https://github.com/Tencent/spring-cloud-tencent/pull/1656)
- [feat: support spring-retry and feign config refresh and feign eager load support schema](https://github.com/Tencent/spring-cloud-tencent/pull/1651)
- [fix: fix ConfigChangeListener ut bug](https://github.com/Tencent/spring-cloud-tencent/pull/1661)
- [fix: tsf 2024 related bugfixes](https://github.com/Tencent/spring-cloud-tencent/pull/1682)

@ -17,32 +17,20 @@
package com.tencent.cloud.metadata.config;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.metadata.core.DecodeTransferMetadataReactiveFilter;
import com.tencent.cloud.metadata.core.DecodeTransferMetadataServletFilter;
import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin;
import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor;
import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin;
import com.tencent.cloud.metadata.core.EncodeTransferMedataScgEnhancedPlugin;
import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer;
import org.springframework.cloud.client.loadbalancer.RetryLoadBalancerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;
import static jakarta.servlet.DispatcherType.ASYNC;
import static jakarta.servlet.DispatcherType.ERROR;
@ -130,59 +118,9 @@ public class MetadataTransferAutoConfiguration {
@ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true)
protected static class MetadataTransferRestTemplateConfig {
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Bean
public EncodeTransferMedataRestTemplateInterceptor encodeTransferMedataRestTemplateInterceptor() {
return new EncodeTransferMedataRestTemplateInterceptor();
}
@Bean
public SmartInitializingSingleton addEncodeTransferMetadataInterceptorForRestTemplate(EncodeTransferMedataRestTemplateInterceptor interceptor) {
return () -> restTemplates.forEach(restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors());
list.add(interceptor);
restTemplate.setInterceptors(list);
});
}
@Bean
public RestTemplateCustomizer polarisRestTemplateCustomizer(
@Autowired(required = false) RetryLoadBalancerInterceptor retryLoadBalancerInterceptor,
@Autowired(required = false) LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors());
// LoadBalancerInterceptor must invoke before EncodeTransferMedataRestTemplateInterceptor
int addIndex = list.size();
if (CollectionUtils.containsInstance(list, retryLoadBalancerInterceptor) || CollectionUtils.containsInstance(list, loadBalancerInterceptor)) {
ClientHttpRequestInterceptor enhancedRestTemplateInterceptor = null;
for (int i = 0; i < list.size(); i++) {
if (list.get(i) instanceof EncodeTransferMedataRestTemplateInterceptor) {
enhancedRestTemplateInterceptor = list.get(i);
addIndex = i;
}
}
if (enhancedRestTemplateInterceptor != null) {
list.remove(addIndex);
list.add(enhancedRestTemplateInterceptor);
}
}
else {
if (retryLoadBalancerInterceptor != null || loadBalancerInterceptor != null) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i) instanceof EncodeTransferMedataRestTemplateInterceptor) {
addIndex = i;
}
}
list.add(addIndex,
retryLoadBalancerInterceptor != null
? retryLoadBalancerInterceptor
: loadBalancerInterceptor);
}
}
restTemplate.setInterceptors(list);
};
public EncodeTransferMedataRestTemplateEnhancedPlugin encodeTransferMedataRestTemplateEnhancedPlugin() {
return new EncodeTransferMedataRestTemplateEnhancedPlugin();
}
}

@ -17,27 +17,23 @@
package com.tencent.cloud.metadata.core;
import java.io.IOException;
import java.util.Map;
import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.tsf.TsfContextUtils;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.common.util.TsfTagUtils;
import com.tencent.cloud.common.util.UrlUtils;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant;
import com.tencent.polaris.metadata.core.MessageMetadataContainer;
import com.tencent.polaris.metadata.core.MetadataType;
import shade.polaris.com.google.common.collect.ImmutableMap;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.core.Ordered;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.util.CollectionUtils;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA;
@ -45,23 +41,23 @@ import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUST
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA;
/**
* Interceptor used for adding the metadata in http headers from context when web client
* is RestTemplate.
* Pre EnhancedPlugin for rest template to encode transfer metadata.
*
* It needs to execute after {@link LoadBalancerInterceptor}, because LaneRouter may add calleeTransitiveHeaders.
*
* @author Haotian Zhang
* @author Shedfree Wu
*/
public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRequestInterceptor, Ordered {
public class EncodeTransferMedataRestTemplateEnhancedPlugin implements EnhancedPlugin {
@Override
public int getOrder() {
return OrderConstant.Client.RestTemplate.ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER;
public EnhancedPluginType getType() {
return EnhancedPluginType.Client.BEFORE_CALLING;
}
@Override
public ClientHttpResponse intercept(@NonNull HttpRequest httpRequest, @NonNull byte[] bytes,
@NonNull ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
public void run(EnhancedPluginContext context) throws Throwable {
if (!(context.getOriginRequest() instanceof HttpRequest)) {
return;
}
HttpRequest httpRequest = (HttpRequest) context.getOriginRequest();
// get metadata of current thread
MetadataContext metadataContext = MetadataContextHolder.get();
Map<String, String> customMetadata = metadataContext.getCustomMetadata();
@ -91,8 +87,6 @@ public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRe
}
// set headers that need to be transmitted from the upstream
this.buildTransmittedHeader(httpRequest, transHeaders);
return clientHttpRequestExecution.execute(httpRequest, bytes);
}
private void buildTransmittedHeader(HttpRequest request, Map<String, String> transHeaders) {
@ -121,4 +115,9 @@ public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRe
buildHeaderMap(request, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata)));
}
}
@Override
public int getOrder() {
return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER;
}
}

@ -22,6 +22,7 @@ import java.util.Map;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.rpc.enhancement.instrument.resttemplate.EnhancedRestTemplateInterceptor;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -43,16 +44,16 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
/**
* Test for {@link EncodeTransferMedataRestTemplateInterceptor}.
* Test for {@link EnhancedRestTemplateInterceptor}.
*
* @author Haotian Zhang
*/
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = RANDOM_PORT,
classes = EncodeTransferMedataRestTemplateInterceptorTest.TestApplication.class,
classes = EnhancedRestTemplateInterceptorTest.TestApplication.class,
properties = {"spring.config.location = classpath:application-test.yml",
"spring.main.web-application-type = reactive"})
public class EncodeTransferMedataRestTemplateInterceptorTest {
public class EnhancedRestTemplateInterceptorTest {
@Autowired
private RestTemplate restTemplate;

@ -65,7 +65,7 @@ public final class ConsulDiscoveryUtil {
if (StringUtils.isNotBlank(appName)) {
return appName;
}
return env.getProperty("spring.application.name", "application");
return env.getProperty("spring.application.name");
}
public static String getInstanceId(ConsulDiscoveryProperties properties, ApplicationContext context) {

@ -25,6 +25,7 @@ import java.util.concurrent.ScheduledExecutorService;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.common.util.OkHttpUtil;
import com.tencent.cloud.common.util.OtUtils;
import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
@ -101,13 +102,18 @@ public class PolarisServiceRegistry implements ServiceRegistry<PolarisRegistrati
@Override
public void register(PolarisRegistration registration) {
if (StringUtils.isBlank(registration.getServiceId())) {
String serviceId = registration.getServiceId();
if (StringUtils.isBlank(serviceId)) {
serviceId = ApplicationContextAwareUtils.getProperties("spring.application.name");
}
if (StringUtils.isBlank(serviceId)) {
LOGGER.warn("No service to register for polaris client...");
return;
}
registration.customize();
String serviceId = registration.getServiceId();
MetadataContext.setLocalService(serviceId);
MetadataContext.setLocalNamespace(polarisDiscoveryProperties.getNamespace());
// Register instance.
InstanceRegisterRequest instanceRegisterRequest = new InstanceRegisterRequest();

@ -76,6 +76,8 @@ public class RouterUtilsTest {
mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext);
Mockito.when(metadataContext.getContext(anyString(), anyString(), anyString()))
.thenReturn(testNamespaceAndService);
Mockito.when(metadataContext.getContext(anyString(), anyString()))
.thenReturn(testNamespaceAndService);
int instanceSize = 100;
int weight = 50;

@ -40,6 +40,14 @@ public final class ContextConstant {
* Default registry heartbeat time interval: 5 (s).
*/
public static final Integer DEFAULT_REGISTRY_HEARTBEAT_TIME_INTERVAL = 5;
/**
* ENHANCED_PLUGIN_CONTEXT.
*/
public static final String ENHANCED_PLUGIN_CONTEXT = "ENHANCED_PLUGIN_CONTEXT";
/**
* LANE_TAG.
*/
public static final String LANE_TAG = "LANE_TAG";
private ContextConstant() {
}
@ -62,4 +70,15 @@ public final class ContextConstant {
}
}
public static final class Trace {
/**
* EXTRA_TRACE_ATTRIBUTES.
*/
public static final String EXTRA_TRACE_ATTRIBUTES = "EXTRA_TRACE_ATTRIBUTES";
private Trace() {
}
}
}

@ -49,14 +49,14 @@ public class OrderConstant {
*/
public static class RestTemplate {
/**
* Order of encode transfer metadata interceptor.
* Order of encode enhance interceptor.
*/
public static final int ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER = Ordered.LOWEST_PRECEDENCE;
public static final int ENHANCE_INTERCEPTOR_ORDER = Ordered.LOWEST_PRECEDENCE;
/**
* Order of encode router label interceptor.
*/
public static final int ROUTER_LABEL_INTERCEPTOR_ORDER = Ordered.LOWEST_PRECEDENCE;
public static final int ROUTER_LABEL_INTERCEPTOR_ORDER = 0;
}
/**

@ -133,6 +133,10 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M
LOCAL_SERVICE = service;
}
public static void setLocalNamespace(String namespace) {
LOCAL_NAMESPACE = namespace;
}
private Map<String, String> getMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean caller) {
MetadataContainer metadataContainer = getMetadataContainer(metadataType, caller);
Map<String, String> values = new HashMap<>();

@ -0,0 +1,49 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 Tencent. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.common.util;
import java.util.Optional;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.polaris.metadata.core.MetadataObjectValue;
import com.tencent.polaris.metadata.core.MetadataType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utils for MetadataContext.
*
* @author Shedfree Wu
*/
public final class MetadataContextUtils {
private static final Logger LOG = LoggerFactory.getLogger(MetadataContextUtils.class);
private MetadataContextUtils() {
}
public static void putMetadataObjectValue(String key, Object value) {
MetadataContextHolder.get().getMetadataContainer(MetadataType.APPLICATION, true).
putMetadataObjectValue(key, value);
}
public static boolean existMetadataValue(MetadataObjectValue<?> metadataObjectValue) {
return Optional.ofNullable(metadataObjectValue).map(MetadataObjectValue::getObjectValue).
map(Optional::isPresent).orElse(false);
}
}

@ -27,6 +27,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import com.tencent.cloud.common.constant.ContextConstant;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.tsf.TsfContextUtils;
import com.tencent.polaris.api.utils.CollectionUtils;
@ -114,6 +115,7 @@ public final class TsfTagUtils {
if (laneTag != null) {
tsfSystemTags.add(laneTag);
MetadataContextUtils.putMetadataObjectValue(ContextConstant.LANE_TAG, laneTag);
}
if (CollectionUtils.isNotEmpty(tsfUserTags)) {

@ -28,9 +28,11 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.tencent.cloud.common.constant.ContextConstant;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.util.MetadataContextUtils;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.api.utils.StringUtils;
import com.tencent.tsf.gateway.core.TsfGatewayRequest;
@ -240,6 +242,7 @@ public class ContextGatewayFilter implements GatewayFilter, Ordered {
throw NotFoundException.create(true, msg);
}
updateRouteMetadata(exchange, contextRoute);
setTraceAttributes(contextRoute, GatewayConstant.NON_UNIT_TYPE, GatewayConstant.NON_UNIT_TRANSFER_TYPE);
exchange.getAttributes().put(GatewayConstant.CONTEXT_ROUTE, contextRoute);
URI requestUri = URI.create(contextRoute.getHost() + apis[1]);
@ -261,6 +264,7 @@ public class ContextGatewayFilter implements GatewayFilter, Ordered {
throw NotFoundException.create(true, msg);
}
updateRouteMetadata(exchange, contextRoute);
setTraceAttributes(contextRoute, GatewayConstant.NON_UNIT_TYPE, GatewayConstant.NON_UNIT_TRANSFER_TYPE);
exchange.getAttributes().put(GatewayConstant.CONTEXT_ROUTE, contextRoute);
MetadataContext metadataContext = exchange.getAttribute(
@ -488,4 +492,22 @@ public class ContextGatewayFilter implements GatewayFilter, Ordered {
throw new IllegalStateException("Invalid URI query: \"" + query + "\"");
}
}
private void setTraceAttributes(GroupContext.ContextRoute contextRoute, String unitType, String unitTransferType) {
Map<String, String> traceAttributes = new HashMap<>();
traceAttributes.put("tsf-ms-type", "MSGW");
traceAttributes.put("tsf-unit-type", unitType);
traceAttributes.put("tsf-unit-transfer-type", unitTransferType);
traceAttributes.put("destination.namespace-id", contextRoute.getNamespaceId());
traceAttributes.put("tsf-msgw-group", config.getGroup());
traceAttributes.put("tsf-msgw-groupApi", contextRoute.getApiId());
traceAttributes.put("tsf-msgw-apiPath", contextRoute.getPath());
traceAttributes.put("tsf-msgw-apiMethod", contextRoute.getMethod());
traceAttributes.put("tsf-msgw-namespaceName", contextRoute.getNamespace());
traceAttributes.put("tsf-msgw-serviceName", contextRoute.getService());
traceAttributes.put("localComponent", "msgw");
MetadataContextUtils.putMetadataObjectValue(ContextConstant.Trace.EXTRA_TRACE_ATTRIBUTES, traceAttributes);
}
}

@ -18,8 +18,10 @@
package com.tencent.cloud.plugin.gateway.context;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URI;
import java.util.ArrayList;
@ -63,6 +65,7 @@ import com.tencent.tsf.gateway.core.model.PathWildcardRule;
import com.tencent.tsf.gateway.core.model.PluginInstanceInfoResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import shade.polaris.org.apache.commons.io.IOUtils;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
@ -126,6 +129,10 @@ public class GatewayConsulRepo {
if (listResponse.getValue() != null) {
refreshGatewayGroupConfig(parseGroupResponse(listResponse));
}
else {
logger.info("try to load gateway group config from local file.");
refreshGatewayGroupConfig(loadResponseFromFile());
}
scheduledExecutorService.scheduleAtFixedRate(() -> {
try {
@ -257,6 +264,35 @@ public class GatewayConsulRepo {
}
private GatewayAllResult loadResponseFromFile() {
GroupResult groupResult = (GroupResult) readLocalRepo(GatewayConstant.GROUP_FILE_NAME, GroupResult.class);
GroupApiResult groupApiResult = (GroupApiResult) readLocalRepo(GatewayConstant.API_FILE_NAME, GroupApiResult.class);
PathRewriteResult pathRewriteResult = (PathRewriteResult) readLocalRepo(GatewayConstant.PATH_REWRITE_FILE_NAME, PathRewriteResult.class);
PathWildcardResult pathWildcardResult = (PathWildcardResult) readLocalRepo(GatewayConstant.PATH_WILDCARD_FILE_NAME, PathWildcardResult.class);
return new GatewayAllResult(groupResult, groupApiResult, pathRewriteResult, pathWildcardResult);
}
private Object readLocalRepo(String type, Class<?> repoResultClazz) {
byte[] bytes;
try (FileInputStream fin = new FileInputStream(getRepoStoreFile(type)); InputStreamReader isr = new InputStreamReader(fin)) {
bytes = IOUtils.toByteArray(isr, "utf-8");
if (bytes == null || bytes.length == 0) {
return null;
}
}
catch (IOException t) {
logger.warn("[readLocalRepo] read group info from file occur exception: {}", t.getMessage());
return null;
}
try {
return JacksonUtils.deserialize(new String(bytes, "utf-8"), repoResultClazz);
}
catch (Throwable t) {
logger.warn("[readLocalRepo] json serialize data to group occur exception: {}", t.getMessage());
return null;
}
}
private GatewayAllResult parseGroupResponse(Response<List<GetValue>> listResponse) {
GroupResult groupResult = null;
GroupApiResult groupApiResult = new GroupApiResult();
@ -362,30 +398,32 @@ public class GatewayConsulRepo {
}
}
for (GroupApi groupApi : groupApiResult.getResult()) {
GroupContext groupContext = groups.get(groupApi.getGroupId());
if (groupContext == null) {
if (logger.isDebugEnabled()) {
logger.debug("group api {} not found in group {}", groupApi.getApiId(), groupApi.getGroupId());
if (groupApiResult != null) {
for (GroupApi groupApi : groupApiResult.getResult()) {
GroupContext groupContext = groups.get(groupApi.getGroupId());
if (groupContext == null) {
if (logger.isDebugEnabled()) {
logger.debug("group api {} not found in group {}", groupApi.getApiId(), groupApi.getGroupId());
}
continue;
}
continue;
}
GroupContext.ContextRoute contextRoute = new GroupContext.ContextRoute();
contextRoute.setApiId(groupApi.getApiId());
contextRoute.setHost(groupApi.getHost());
contextRoute.setPath(groupApi.getPath());
contextRoute.setPathMapping(groupApi.getPathMapping());
contextRoute.setMethod(groupApi.getMethod());
contextRoute.setService(groupApi.getServiceName());
contextRoute.setNamespaceId(groupApi.getNamespaceId());
contextRoute.setNamespace(groupApi.getNamespaceName());
if (groupApi.getTimeout() != null) {
Map<String, String> metadata = new HashMap<>();
metadata.put("response-timeout", String.valueOf(groupApi.getTimeout()));
contextRoute.setMetadata(metadata);
GroupContext.ContextRoute contextRoute = new GroupContext.ContextRoute();
contextRoute.setApiId(groupApi.getApiId());
contextRoute.setHost(groupApi.getHost());
contextRoute.setPath(groupApi.getPath());
contextRoute.setPathMapping(groupApi.getPathMapping());
contextRoute.setMethod(groupApi.getMethod());
contextRoute.setService(groupApi.getServiceName());
contextRoute.setNamespaceId(groupApi.getNamespaceId());
contextRoute.setNamespace(groupApi.getNamespaceName());
if (groupApi.getTimeout() != null) {
Map<String, String> metadata = new HashMap<>();
metadata.put("response-timeout", String.valueOf(groupApi.getTimeout()));
contextRoute.setMetadata(metadata);
}
groupContext.getRoutes().add(contextRoute);
}
groupContext.getRoutes().add(contextRoute);
}
if (pathWildcardResult != null && pathWildcardResult.getResult() != null) {
@ -410,7 +448,7 @@ public class GatewayConsulRepo {
contextGatewayProperties.setGroups(groups);
contextGatewayProperties.setRoutes(routes);
contextGatewayProperties.setPathRewrites(Optional.ofNullable(pathRewriteResult.getResult())
contextGatewayProperties.setPathRewrites(Optional.ofNullable(pathRewriteResult).map(PathRewriteResult::getResult)
.orElse(new ArrayList<>()));
logger.debug("Gateway config loaded. :{}", JacksonUtils.serialize2Json(contextGatewayProperties));

@ -74,6 +74,22 @@ public final class GatewayConstant {
* Gateway .
*/
public static final String GATEWAY_REPO_PREFIX = GATEWAY_REPO_ROOT + "/tsf/gateway/";
/**
* NON_UNIT_TYPE.
*/
public static final String NON_UNIT_TYPE = "non-unit";
/**
* NON_UNIT_TRANSFER_TYPE.
*/
public static final String NON_UNIT_TRANSFER_TYPE = "non-unit";
/**
* UNIT_TYPE.
*/
public static final String UNIT_TYPE = "unit";
/**
* UNIT_TRANSFER_TYPE.
*/
public static final String UNIT_TRANSFER_TYPE = "ms_unit_proxy";
private GatewayConstant() {

@ -28,6 +28,7 @@ import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.plugin.gateway.context.Position;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import com.tencent.polaris.api.utils.ClassUtils;
import com.tencent.polaris.api.utils.StringUtils;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import com.tencent.polaris.assembly.api.pojo.TraceAttributes;
@ -39,6 +40,7 @@ import com.tencent.tsf.gateway.core.http.HttpConnectionPoolUtil;
import com.tencent.tsf.gateway.core.model.OAuthPlugin;
import com.tencent.tsf.gateway.core.model.OAuthResult;
import com.tencent.tsf.gateway.core.model.PluginPayload;
import io.opentelemetry.context.Scope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -196,7 +198,7 @@ public class OAuthGatewayPlugin implements IGatewayPlugin<OAuthPlugin> {
throw new TsfGatewayException(TsfGatewayError.GATEWAY_REQUEST_NOT_FOUND, "Unable to find instance for " + pluginInfo.getTokenAuthServiceName());
}
fillTracingContext(namespace, serviceName);
Object otScope = fillTracingContext(namespace, serviceName);
String newRequestUrl = uri.getScheme() + "://" + GATEWAY_WILDCARD_SERVICE_NAME + tokenAuthUrl;
URI newUri = new URI(newRequestUrl);
@ -204,7 +206,12 @@ public class OAuthGatewayPlugin implements IGatewayPlugin<OAuthPlugin> {
// http://127.0.0.1:8080/group1/namespace1/Consumer-demo/echo-rest/1?user=1
URI requestUrl = this.reconstructURI(new OauthDelegatingServiceInstance(instance.getServer()), newUri);
logger.debug("LoadBalancerClientFilter url chosen: " + requestUrl);
return sendAuthRequestByHttpMethod(paramsMap, headerParamsMap, requestUrl.toASCIIString(), tokenAuthMethod, timeout);
String result = sendAuthRequestByHttpMethod(paramsMap, headerParamsMap, requestUrl.toASCIIString(), tokenAuthMethod, timeout);
if (ClassUtils.isClassPresent("io.opentelemetry.context.Scope") && otScope instanceof Scope) {
((Scope) otScope).close();
}
return result;
}
catch (Exception e) {
logger.error("MicroService {} Request Auth Server Error", tokenAuthMethod, e);
@ -244,7 +251,7 @@ public class OAuthGatewayPlugin implements IGatewayPlugin<OAuthPlugin> {
}
}
void fillTracingContext(String namespace, String serviceName) {
Object fillTracingContext(String namespace, String serviceName) {
Map<String, String> attributes = new HashMap<>();
attributes.put("net.peer.service", serviceName);
@ -256,6 +263,8 @@ public class OAuthGatewayPlugin implements IGatewayPlugin<OAuthPlugin> {
AssemblyAPI assemblyAPI = polarisSDKContextManager.getAssemblyAPI();
assemblyAPI.updateTraceAttributes(traceAttributes);
return traceAttributes.getOtScope();
}
class OauthDelegatingServiceInstance implements ServiceInstance {

@ -44,7 +44,7 @@ public class TraceClientPreEnhancedPlugin implements EnhancedPlugin {
@Override
public EnhancedPluginType getType() {
return EnhancedPluginType.Client.PRE;
return EnhancedPluginType.Client.BEFORE_CALLING;
}
@Override

@ -0,0 +1,74 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 Tencent. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.plugin.trace;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.tencent.cloud.plugin.trace.attribute.SpanAttributesProvider;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import com.tencent.polaris.assembly.api.pojo.TraceAttributes;
public class TraceServerFinallyEnhancedPlugin implements EnhancedPlugin {
private final PolarisSDKContextManager polarisSDKContextManager;
private final List<SpanAttributesProvider> spanAttributesProviderList;
public TraceServerFinallyEnhancedPlugin(PolarisSDKContextManager polarisSDKContextManager, List<SpanAttributesProvider> spanAttributesProviderList) {
this.polarisSDKContextManager = polarisSDKContextManager;
this.spanAttributesProviderList = spanAttributesProviderList;
}
@Override
public EnhancedPluginType getType() {
return EnhancedPluginType.Server.FINALLY;
}
@Override
public void run(EnhancedPluginContext context) throws Throwable {
Map<String, String> attributes = new HashMap<>();
if (CollectionUtils.isNotEmpty(spanAttributesProviderList)) {
for (SpanAttributesProvider spanAttributesProvider : spanAttributesProviderList) {
Map<String, String> additionalAttributes = spanAttributesProvider.getServerFinallySpanAttributes(context);
if (CollectionUtils.isNotEmpty(additionalAttributes)) {
attributes.putAll(additionalAttributes);
}
}
}
TraceAttributes traceAttributes = new TraceAttributes();
traceAttributes.setAttributes(attributes);
traceAttributes.setAttributeLocation(TraceAttributes.AttributeLocation.SPAN);
AssemblyAPI assemblyAPI = polarisSDKContextManager.getAssemblyAPI();
assemblyAPI.updateTraceAttributes(traceAttributes);
}
@Override
public int getOrder() {
return PluginOrderConstant.ServerPluginOrder.TRACE_SERVER_PRE_PLUGIN_ORDER;
}
}

@ -52,7 +52,7 @@ public class TraceServerPreEnhancedPlugin implements EnhancedPlugin {
Map<String, String> attributes = new HashMap<>();
if (CollectionUtils.isNotEmpty(spanAttributesProviderList)) {
for (SpanAttributesProvider spanAttributesProvider : spanAttributesProviderList) {
Map<String, String> additionalAttributes = spanAttributesProvider.getServerSpanAttributes(context);
Map<String, String> additionalAttributes = spanAttributesProvider.getServerPreSpanAttributes(context);
if (CollectionUtils.isNotEmpty(additionalAttributes)) {
attributes.putAll(additionalAttributes);
}

@ -20,6 +20,7 @@ package com.tencent.cloud.plugin.trace.attribute;
import java.util.HashMap;
import java.util.Map;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
@ -40,7 +41,7 @@ import static com.tencent.polaris.plugins.router.lane.LaneRouter.TRAFFIC_STAIN_L
*/
public class PolarisSpanAttributesProvider implements SpanAttributesProvider {
@Override
public Map<String, String> getServerSpanAttributes(EnhancedPluginContext context) {
public Map<String, String> getServerPreSpanAttributes(EnhancedPluginContext context) {
Map<String, String> attributes = new HashMap<>();
MetadataContext metadataContext = MetadataContextHolder.get();
Map<String, String> transitiveCustomAttributes = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
@ -59,6 +60,9 @@ public class PolarisSpanAttributesProvider implements SpanAttributesProvider {
if (CollectionUtils.isNotEmpty(upstreamDisposableCustomAttributes)) {
for (Map.Entry<String, String> entry : upstreamDisposableCustomAttributes.entrySet()) {
attributes.put("custom." + entry.getKey(), entry.getValue());
if (MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAME.equals(entry.getKey())) {
attributes.put("net.peer.service", entry.getValue());
}
}
}
attributes.put("http.port", CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer()

@ -29,7 +29,11 @@ public interface SpanAttributesProvider {
*/
String OT_SCOPE_KEY = "OT_SCOPE_KEY";
default Map<String, String> getServerSpanAttributes(EnhancedPluginContext context) {
default Map<String, String> getServerPreSpanAttributes(EnhancedPluginContext context) {
return new HashMap<>();
}
default Map<String, String> getServerFinallySpanAttributes(EnhancedPluginContext context) {
return new HashMap<>();
}

@ -20,13 +20,22 @@ package com.tencent.cloud.plugin.trace.attribute.tsf;
import java.util.HashMap;
import java.util.Map;
import com.tencent.cloud.common.constant.ContextConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.util.MetadataContextUtils;
import com.tencent.cloud.common.util.OtUtils;
import com.tencent.cloud.plugin.trace.attribute.SpanAttributesProvider;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.api.utils.StringUtils;
import com.tencent.polaris.metadata.core.MetadataObjectValue;
import com.tencent.polaris.metadata.core.MetadataType;
import com.tencent.polaris.metadata.core.constant.TsfMetadataConstants;
import com.tencent.polaris.plugins.router.lane.LaneRouter;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.tsf.core.entity.Tag;
public class TsfSpanAttributesProvider implements SpanAttributesProvider {
@ -54,6 +63,50 @@ public class TsfSpanAttributesProvider implements SpanAttributesProvider {
if (StringUtils.isBlank(attributes.get("remote.namespace-id"))) {
attributes.put("remote.namespace-id", context.getRequest().getGovernanceNamespace());
}
MetadataObjectValue<Tag> langTagObject = MetadataContextHolder.get().
getMetadataContainer(MetadataType.APPLICATION, true).
getMetadataValue(ContextConstant.LANE_TAG);
if (MetadataContextUtils.existMetadataValue(langTagObject)) {
attributes.put(OtUtils.OTEL_LANE_ID_KEY, langTagObject.getObjectValue().get().getValue());
}
MetadataObjectValue<Map<String, String>> extraTraceAttributeObject = MetadataContextHolder.get().
getMetadataContainer(MetadataType.APPLICATION, true).
getMetadataValue(ContextConstant.Trace.EXTRA_TRACE_ATTRIBUTES);
if (MetadataContextUtils.existMetadataValue(extraTraceAttributeObject)) {
Map<String, String> extraTraceAttributes = extraTraceAttributeObject.getObjectValue().get();
attributes.putAll(extraTraceAttributes);
}
return attributes;
}
@Override
public Map<String, String> getServerPreSpanAttributes(EnhancedPluginContext context) {
Map<String, String> attributes = new HashMap<>();
MetadataContext metadataContext = MetadataContextHolder.get();
Map<String, String> upstreamDisposableCustomAttributes = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_UPSTREAM_DISPOSABLE);
if (CollectionUtils.isNotEmpty(upstreamDisposableCustomAttributes)) {
for (Map.Entry<String, String> entry : upstreamDisposableCustomAttributes.entrySet()) {
if (LaneRouter.TRAFFIC_STAIN_LABEL.equals(entry.getKey()) && entry.getValue().startsWith("tsf/")) {
attributes.put(OtUtils.OTEL_LANE_ID_KEY, entry.getValue().split("/")[1]);
}
}
}
return attributes;
}
@Override
public Map<String, String> getServerFinallySpanAttributes(EnhancedPluginContext context) {
Map<String, String> attributes = new HashMap<>();
MetadataObjectValue<Map<String, String>> extraTraceAttributeObject = MetadataContextHolder.get().
getMetadataContainer(MetadataType.APPLICATION, true).
getMetadataValue(ContextConstant.Trace.EXTRA_TRACE_ATTRIBUTES);
if (MetadataContextUtils.existMetadataValue(extraTraceAttributeObject)) {
Map<String, String> extraTraceAttributes = extraTraceAttributeObject.getObjectValue().get();
attributes.putAll(extraTraceAttributes);
}
return attributes;
}
}

@ -21,6 +21,7 @@ import java.util.List;
import com.tencent.cloud.plugin.trace.TraceClientFinallyEnhancedPlugin;
import com.tencent.cloud.plugin.trace.TraceClientPreEnhancedPlugin;
import com.tencent.cloud.plugin.trace.TraceServerFinallyEnhancedPlugin;
import com.tencent.cloud.plugin.trace.TraceServerPreEnhancedPlugin;
import com.tencent.cloud.plugin.trace.attribute.PolarisSpanAttributesProvider;
import com.tencent.cloud.plugin.trace.attribute.SpanAttributesProvider;
@ -46,6 +47,12 @@ public class TraceEnhancedPluginAutoConfiguration {
return new TraceServerPreEnhancedPlugin(polarisSDKContextManager, spanAttributesProviderList);
}
@Bean
public TraceServerFinallyEnhancedPlugin traceServerFinallyEnhancedPlugin(
PolarisSDKContextManager polarisSDKContextManager, @Autowired(required = false) List<SpanAttributesProvider> spanAttributesProviderList) {
return new TraceServerFinallyEnhancedPlugin(polarisSDKContextManager, spanAttributesProviderList);
}
@Bean
public TraceClientPreEnhancedPlugin traceClientPreEnhancedPlugin(
PolarisSDKContextManager polarisSDKContextManager, @Autowired(required = false) List<SpanAttributesProvider> spanAttributesProviderList) {

@ -40,7 +40,7 @@ public class PostInitPolarisSDKContext {
if (StringUtils.isNotBlank(region)) {
valueContext.setValue(RoutingProto.NearbyRoutingConfig.LocationLevel.REGION.name(), region);
}
if (StringUtils.isNotBlank(zone)) {
if (zone != null) {
valueContext.setValue(RoutingProto.NearbyRoutingConfig.LocationLevel.ZONE.name(), zone);
}
if (StringUtils.isNotBlank(campus)) {

@ -96,7 +96,7 @@ public final class PolarisContextEnvironmentPostProcessor implements Environment
// zone
String zone = environment.getProperty("tsf_zone");
if (StringUtils.isNotBlank(zone)) {
if (zone != null) {
polarisEnvProperties.put("spring.cloud.tencent.metadata.content.zone", zone);
}

@ -68,7 +68,7 @@ public class TsfInstanceMetadataProvider implements InstanceMetadataProvider {
tsfMetadata.put(TsfMetadataConstants.TSF_REGION, tsfCoreProperties.getTsfRegion());
}
if (StringUtils.isNotBlank(tsfCoreProperties.getTsfZone())) {
if (tsfCoreProperties.getTsfZone() != null) {
tsfMetadata.put(TsfMetadataConstants.TSF_ZONE, tsfCoreProperties.getTsfZone());
}

@ -17,6 +17,7 @@
package com.tencent.cloud.rpc.enhancement.config;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -28,6 +29,7 @@ import com.tencent.cloud.rpc.enhancement.instrument.feign.EnhancedFeignBeanPostP
import com.tencent.cloud.rpc.enhancement.instrument.feign.PolarisLoadBalancerFeignRequestTransformer;
import com.tencent.cloud.rpc.enhancement.instrument.filter.EnhancedReactiveFilter;
import com.tencent.cloud.rpc.enhancement.instrument.filter.EnhancedServletFilter;
import com.tencent.cloud.rpc.enhancement.instrument.resttemplate.EnhancedRestTemplateInterceptor;
import com.tencent.cloud.rpc.enhancement.instrument.resttemplate.PolarisLoadBalancerRequestTransformer;
import com.tencent.cloud.rpc.enhancement.instrument.scg.EnhancedGatewayGlobalFilter;
import com.tencent.cloud.rpc.enhancement.instrument.webclient.EnhancedWebClientExchangeFilterFunction;
@ -53,12 +55,17 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer;
import org.springframework.cloud.client.loadbalancer.RetryLoadBalancerInterceptor;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Role;
import org.springframework.core.annotation.Order;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
@ -194,7 +201,60 @@ public class RpcEnhancementAutoConfiguration {
public BlockingLoadBalancerClientBeanPostProcessor loadBalancerInterceptorBeanPostProcessor() {
return new BlockingLoadBalancerClientBeanPostProcessor();
}
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Bean
public EnhancedRestTemplateInterceptor enhancedRestTemplateInterceptor(EnhancedPluginRunner pluginRunner) {
return new EnhancedRestTemplateInterceptor(pluginRunner);
}
@Bean
public SmartInitializingSingleton addEncodeTransferMetadataInterceptorForRestTemplate(EnhancedRestTemplateInterceptor interceptor) {
return () -> restTemplates.forEach(restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors());
list.add(interceptor);
restTemplate.setInterceptors(list);
});
}
@Bean
public RestTemplateCustomizer polarisRestTemplateCustomizer(
@Autowired(required = false) RetryLoadBalancerInterceptor retryLoadBalancerInterceptor,
@Autowired(required = false) LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors());
// LoadBalancerInterceptor must invoke before EncodeTransferMedataRestTemplateInterceptor
int addIndex = list.size();
if (CollectionUtils.containsInstance(list, retryLoadBalancerInterceptor) || CollectionUtils.containsInstance(list, loadBalancerInterceptor)) {
ClientHttpRequestInterceptor enhancedRestTemplateInterceptor = null;
for (int i = 0; i < list.size(); i++) {
if (list.get(i) instanceof EnhancedRestTemplateInterceptor) {
enhancedRestTemplateInterceptor = list.get(i);
addIndex = i;
}
}
if (enhancedRestTemplateInterceptor != null) {
list.remove(addIndex);
list.add(enhancedRestTemplateInterceptor);
}
}
else {
if (retryLoadBalancerInterceptor != null || loadBalancerInterceptor != null) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i) instanceof EnhancedRestTemplateInterceptor) {
addIndex = i;
}
}
list.add(addIndex,
retryLoadBalancerInterceptor != null
? retryLoadBalancerInterceptor
: loadBalancerInterceptor);
}
}
restTemplate.setInterceptors(list);
};
}
}

@ -26,11 +26,15 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.cloud.rpc.enhancement.util.EnhancedPluginUtils;
import com.tencent.polaris.api.pojo.CircuitBreakerStatus;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
import feign.Client;
@ -63,7 +67,7 @@ public class EnhancedFeignClient implements Client {
@Override
public Response execute(Request request, Options options) throws IOException {
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
EnhancedPluginContext enhancedPluginContext = EnhancedPluginUtils.createEnhancedPluginContext();
HttpHeaders requestHeaders = new HttpHeaders();
request.headers().forEach((s, strings) -> requestHeaders.addAll(s, new ArrayList<>(strings)));
@ -71,11 +75,15 @@ public class EnhancedFeignClient implements Client {
URI serviceUrl = url.resolve(request.requestTemplate().url());
String governanceNamespace = MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_APPLICATION_NONE,
MetadataConstant.POLARIS_TARGET_NAMESPACE, MetadataContext.LOCAL_NAMESPACE);
EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpHeaders(requestHeaders)
.httpMethod(HttpMethod.valueOf(request.httpMethod().name()))
.url(url)
.serviceUrl(serviceUrl)
.governanceNamespace(governanceNamespace)
.build();
enhancedPluginContext.setRequest(enhancedRequestContext);
enhancedPluginContext.setOriginRequest(request);
@ -97,6 +105,7 @@ public class EnhancedFeignClient implements Client {
try {
// Run pre enhanced plugins.
pluginRunner.run(EnhancedPluginType.Client.PRE, enhancedPluginContext);
pluginRunner.run(EnhancedPluginType.Client.BEFORE_CALLING, enhancedPluginContext);
startMillis = System.currentTimeMillis();
Response response = delegate.execute(request, options);

@ -17,12 +17,16 @@
package com.tencent.cloud.rpc.enhancement.instrument.filter;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.cloud.rpc.enhancement.util.EnhancedPluginUtils;
import reactor.core.publisher.Mono;
import org.springframework.core.Ordered;
@ -45,7 +49,7 @@ public class EnhancedReactiveFilter implements WebFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
EnhancedPluginContext enhancedPluginContext = EnhancedPluginUtils.createEnhancedPluginContext();
EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpHeaders(exchange.getRequest().getHeaders())
@ -80,6 +84,10 @@ public class EnhancedReactiveFilter implements WebFilter, Ordered {
pluginRunner.run(EnhancedPluginType.Server.EXCEPTION, enhancedPluginContext);
})
.doFinally(v -> {
if (exchange.getAttributes().containsKey(MetadataConstant.HeaderName.METADATA_CONTEXT)) {
MetadataContextHolder.set((MetadataContext) exchange.getAttributes().get(
MetadataConstant.HeaderName.METADATA_CONTEXT));
}
// Run finally enhanced plugins.
pluginRunner.run(EnhancedPluginType.Server.FINALLY, enhancedPluginContext);
});

@ -30,6 +30,7 @@ import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.cloud.rpc.enhancement.util.EnhancedPluginUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
@ -56,7 +57,7 @@ public class EnhancedServletFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
EnhancedPluginContext enhancedPluginContext = EnhancedPluginUtils.createEnhancedPluginContext();
HttpHeaders requestHeaders = new HttpHeaders();
Enumeration<String> requestHeaderNames = request.getHeaderNames();

@ -22,12 +22,15 @@ import java.net.URI;
import java.util.Optional;
import com.tencent.cloud.common.constant.ContextConstant;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.cloud.rpc.enhancement.util.EnhancedPluginUtils;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
import com.tencent.polaris.metadata.core.MetadataObjectValue;
import com.tencent.polaris.metadata.core.MetadataType;
@ -42,17 +45,17 @@ import org.springframework.http.client.ClientHttpResponse;
import static com.tencent.cloud.rpc.enhancement.instrument.resttemplate.PolarisLoadBalancerRequestTransformer.LOAD_BALANCER_SERVICE_INSTANCE;
/**
* EnhancedRestTemplateInterceptor.
* Interceptor used for pre-plugin, post-plugin, exception-plugin, and final-plugin in RestTemplate.
*
* @author sean yu
*/
public class EnhancedRestTemplateWrapInterceptor {
public class EnhancedRestTemplateBlockingLoadBalancerClientInterceptor {
private final EnhancedPluginRunner pluginRunner;
private final LoadBalancerClient delegate;
public EnhancedRestTemplateWrapInterceptor(EnhancedPluginRunner pluginRunner, LoadBalancerClient delegate) {
public EnhancedRestTemplateBlockingLoadBalancerClientInterceptor(EnhancedPluginRunner pluginRunner, LoadBalancerClient delegate) {
this.pluginRunner = pluginRunner;
this.delegate = delegate;
}
@ -61,18 +64,22 @@ public class EnhancedRestTemplateWrapInterceptor {
public <T> T intercept(HttpRequest httpRequest, String serviceId, ServiceInstance serviceInstance,
LoadBalancerRequest<T> loadBalancerRequest) throws IOException {
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
EnhancedPluginContext enhancedPluginContext = EnhancedPluginUtils.createEnhancedPluginContext();
URI serviceUrl = httpRequest.getURI();
if (httpRequest instanceof ServiceRequestWrapper) {
serviceUrl = ((ServiceRequestWrapper) httpRequest).getRequest().getURI();
}
String governanceNamespace = MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_APPLICATION_NONE,
MetadataConstant.POLARIS_TARGET_NAMESPACE, MetadataContext.LOCAL_NAMESPACE);
EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpHeaders(httpRequest.getHeaders())
.httpMethod(httpRequest.getMethod())
.url(httpRequest.getURI())
.serviceUrl(serviceUrl)
.governanceNamespace(governanceNamespace)
.build();
enhancedPluginContext.setRequest(enhancedRequestContext);
enhancedPluginContext.setOriginRequest(httpRequest);

@ -0,0 +1,75 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 Tencent. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.instrument.resttemplate;
import java.io.IOException;
import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.util.EnhancedPluginUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.core.Ordered;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.NonNull;
/**
* Interceptor used for before calling plugin in RestTemplate.
*
* It needs to execute after {@link LoadBalancerInterceptor}, because LaneRouter may add calleeTransitiveHeaders.
*
* @author Haotian Zhang
*/
public class EnhancedRestTemplateInterceptor implements ClientHttpRequestInterceptor, Ordered {
private static final Logger LOG = LoggerFactory.getLogger(EnhancedRestTemplateInterceptor.class);
private final EnhancedPluginRunner pluginRunner;
public EnhancedRestTemplateInterceptor(EnhancedPluginRunner pluginRunner) {
this.pluginRunner = pluginRunner;
}
@Override
public int getOrder() {
return OrderConstant.Client.RestTemplate.ENHANCE_INTERCEPTOR_ORDER;
}
@Override
public ClientHttpResponse intercept(@NonNull HttpRequest httpRequest, @NonNull byte[] bytes,
@NonNull ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
EnhancedPluginContext enhancedPluginContext = EnhancedPluginUtils.getEnhancedPluginContextFromMetadataContext();
if (enhancedPluginContext != null) {
pluginRunner.run(EnhancedPluginType.Client.BEFORE_CALLING, enhancedPluginContext);
}
else {
LOG.debug("No exist enhanced plugin context, request:{}", httpRequest.getURI());
}
return clientHttpRequestExecution.execute(httpRequest, bytes);
}
}

@ -55,8 +55,8 @@ public class PolarisBlockingLoadBalancerClient extends BlockingLoadBalancerClien
if (httpRequest == null || enhancedPluginRunner == null) {
return delegate.execute(serviceId, request);
}
EnhancedRestTemplateWrapInterceptor enhancedRestTemplateWrapInterceptor = new EnhancedRestTemplateWrapInterceptor(enhancedPluginRunner, delegate);
return enhancedRestTemplateWrapInterceptor.intercept(httpRequest, serviceId, null, request);
EnhancedRestTemplateBlockingLoadBalancerClientInterceptor enhancedRestTemplateBlockingLoadBalancerClientInterceptor = new EnhancedRestTemplateBlockingLoadBalancerClientInterceptor(enhancedPluginRunner, delegate);
return enhancedRestTemplateBlockingLoadBalancerClientInterceptor.intercept(httpRequest, serviceId, null, request);
}
/**
@ -68,7 +68,7 @@ public class PolarisBlockingLoadBalancerClient extends BlockingLoadBalancerClien
if (httpRequest == null || serviceInstance == null || enhancedPluginRunner == null) {
return delegate.execute(serviceId, serviceInstance, request);
}
EnhancedRestTemplateWrapInterceptor enhancedRestTemplateWrapInterceptor = new EnhancedRestTemplateWrapInterceptor(enhancedPluginRunner, delegate);
return enhancedRestTemplateWrapInterceptor.intercept(httpRequest, serviceId, serviceInstance, request);
EnhancedRestTemplateBlockingLoadBalancerClientInterceptor enhancedRestTemplateBlockingLoadBalancerClientInterceptor = new EnhancedRestTemplateBlockingLoadBalancerClientInterceptor(enhancedPluginRunner, delegate);
return enhancedRestTemplateBlockingLoadBalancerClientInterceptor.intercept(httpRequest, serviceId, serviceInstance, request);
}
}

@ -18,6 +18,8 @@
package com.tencent.cloud.rpc.enhancement.instrument.resttemplate;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.util.EnhancedPluginUtils;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestTransformer;
@ -45,6 +47,10 @@ public class PolarisLoadBalancerRequestTransformer implements LoadBalancerReques
public HttpRequest transformRequest(HttpRequest request, ServiceInstance instance) {
if (instance != null) {
MetadataContextHolder.get().setLoadbalancer(LOAD_BALANCER_SERVICE_INSTANCE, instance);
EnhancedPluginContext enhancedPluginContext = EnhancedPluginUtils.getEnhancedPluginContextFromMetadataContext();
if (enhancedPluginContext != null) {
enhancedPluginContext.setTargetServiceInstance(instance, request.getURI());
}
}
return request;
}

@ -30,6 +30,7 @@ import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.cloud.rpc.enhancement.util.EnhancedPluginUtils;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.api.utils.StringUtils;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
@ -83,7 +84,7 @@ public class EnhancedGatewayGlobalFilter implements GlobalFilter, Ordered {
MetadataConstant.POLARIS_TARGET_NAMESPACE, MetadataContext.LOCAL_NAMESPACE);
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
EnhancedPluginContext enhancedPluginContext = EnhancedPluginUtils.createEnhancedPluginContext();
EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpHeaders(originExchange.getRequest().getHeaders())
@ -137,6 +138,7 @@ public class EnhancedGatewayGlobalFilter implements GlobalFilter, Ordered {
enhancedPluginContext.setTargetServiceInstance(null, uri);
}
}
pluginRunner.run(EnhancedPluginType.Client.BEFORE_CALLING, enhancedPluginContext);
})
.doOnSuccess(v -> {
MetadataContext metadataContextOnSuccess = originExchange.getAttribute(

@ -21,12 +21,15 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.Optional;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.cloud.rpc.enhancement.util.EnhancedPluginUtils;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
import reactor.core.publisher.Mono;
@ -54,13 +57,17 @@ public class EnhancedWebClientExchangeFilterFunction implements ExchangeFilterFu
@Override
public Mono<ClientResponse> filter(ClientRequest originRequest, ExchangeFunction next) {
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
EnhancedPluginContext enhancedPluginContext = EnhancedPluginUtils.createEnhancedPluginContext();
String governanceNamespace = MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_APPLICATION_NONE,
MetadataConstant.POLARIS_TARGET_NAMESPACE, MetadataContext.LOCAL_NAMESPACE);
EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpHeaders(originRequest.headers())
.httpMethod(originRequest.method())
.url(originRequest.url())
.serviceUrl(getServiceUri(originRequest))
.governanceNamespace(governanceNamespace)
.build();
enhancedPluginContext.setRequest(enhancedRequestContext);
enhancedPluginContext.setOriginRequest(originRequest);
@ -72,6 +79,7 @@ public class EnhancedWebClientExchangeFilterFunction implements ExchangeFilterFu
// Run post enhanced plugins.
try {
pluginRunner.run(EnhancedPluginType.Client.PRE, enhancedPluginContext);
pluginRunner.run(EnhancedPluginType.Client.BEFORE_CALLING, enhancedPluginContext);
}
catch (CallAbortedException e) {
// Run finally enhanced plugins.

@ -29,6 +29,10 @@ public interface EnhancedPluginType {
* Pre Client plugin.
*/
PRE,
/**
* Before calling the Client plugin.
*/
BEFORE_CALLING,
/**
* Post Client plugin.

@ -70,7 +70,7 @@ public class PluginOrderConstant {
* and
* {@link com.tencent.cloud.plugin.trace.TraceClientFinallyEnhancedPlugin}.
*/
public static final int TRACE_CLIENT_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 3;
public static final int TRACE_CLIENT_PLUGIN_ORDER = CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER + 3;
}
public static class ServerPluginOrder {

@ -23,6 +23,8 @@ import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.pojo.PolarisServiceInstance;
import com.tencent.polaris.api.pojo.DefaultInstance;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.api.utils.StringUtils;
import com.tencent.polaris.metadata.core.constant.TsfMetadataConstants;
import org.springframework.cloud.client.ServiceInstance;
@ -47,7 +49,16 @@ public class PolarisInstanceTransformer implements InstanceTransformer {
}
String namespace = MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_APPLICATION_NONE,
MetadataConstant.POLARIS_TARGET_NAMESPACE, instance.getNamespace());
MetadataConstant.POLARIS_TARGET_NAMESPACE);
if (StringUtils.isBlank(namespace) && serviceInstance.getMetadata() != null &&
serviceInstance.getMetadata().containsKey(TsfMetadataConstants.TSF_NAMESPACE_ID)) {
namespace = serviceInstance.getMetadata().get(TsfMetadataConstants.TSF_NAMESPACE_ID);
}
if (StringUtils.isBlank(namespace)) {
namespace = instance.getNamespace();
}
instance.setNamespace(namespace);
}

@ -0,0 +1,54 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 Tencent. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.util;
import com.tencent.cloud.common.constant.ContextConstant;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.util.MetadataContextUtils;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.polaris.metadata.core.MetadataObjectValue;
import com.tencent.polaris.metadata.core.MetadataType;
/**
* EnhancedPluginUtils.
*
* @author Shedfree Wu
*/
public final class EnhancedPluginUtils {
private EnhancedPluginUtils() {
}
public static EnhancedPluginContext createEnhancedPluginContext() {
EnhancedPluginContext context = new EnhancedPluginContext();
MetadataContextUtils.putMetadataObjectValue(ContextConstant.ENHANCED_PLUGIN_CONTEXT, context);
return context;
}
public static EnhancedPluginContext getEnhancedPluginContextFromMetadataContext() {
MetadataObjectValue<EnhancedPluginContext> enhancedPluginContextObject = MetadataContextHolder.get().
getMetadataContainer(MetadataType.APPLICATION, true).
getMetadataValue(ContextConstant.ENHANCED_PLUGIN_CONTEXT);
if (MetadataContextUtils.existMetadataValue(enhancedPluginContextObject)) {
return enhancedPluginContextObject.getObjectValue().get();
}
return null;
}
}
Loading…
Cancel
Save