pull/962/head
seanyu 2 years ago
parent ec1b11ff55
commit 02f04d7d0a

@ -22,6 +22,8 @@ import java.util.List;
import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory;
import com.tencent.cloud.polaris.circuitbreaker.common.CircuitBreakerConfigModifier;
import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter;
import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter;
import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreakerRestTemplateBeanPostProcessor;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
@ -61,6 +63,20 @@ public class PolarisCircuitBreakerAutoConfiguration {
return CircuitBreakAPIFactory.createCircuitBreakAPIByContext(polarisContext);
}
@Bean
@ConditionalOnMissingBean(SuccessCircuitBreakerReporter.class)
public SuccessCircuitBreakerReporter successCircuitBreakerReporter(RpcEnhancementReporterProperties properties,
SDKContext polarisContext, CircuitBreakAPI circuitBreakAPI) {
return new SuccessCircuitBreakerReporter(properties, polarisContext, circuitBreakAPI);
}
@Bean
@ConditionalOnMissingBean(ExceptionCircuitBreakerReporter.class)
public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhancementReporterProperties properties,
SDKContext polarisContext, CircuitBreakAPI circuitBreakAPI) {
return new ExceptionCircuitBreakerReporter(properties, polarisContext, circuitBreakAPI);
}
@Bean
@ConditionalOnMissingBean(CircuitBreakerFactory.class)
public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) {

@ -22,6 +22,8 @@ import java.util.List;
import com.tencent.cloud.polaris.circuitbreaker.ReactivePolarisCircuitBreakerFactory;
import com.tencent.cloud.polaris.circuitbreaker.common.CircuitBreakerConfigModifier;
import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter;
import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.polaris.api.core.ConsumerAPI;
@ -59,6 +61,20 @@ public class ReactivePolarisCircuitBreakerAutoConfiguration {
return CircuitBreakAPIFactory.createCircuitBreakAPIByContext(polarisContext);
}
@Bean
@ConditionalOnMissingBean(SuccessCircuitBreakerReporter.class)
public SuccessCircuitBreakerReporter successCircuitBreakerReporter(RpcEnhancementReporterProperties properties,
SDKContext polarisContext, CircuitBreakAPI circuitBreakAPI) {
return new SuccessCircuitBreakerReporter(properties, polarisContext, circuitBreakAPI);
}
@Bean
@ConditionalOnMissingBean(ExceptionCircuitBreakerReporter.class)
public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhancementReporterProperties properties,
SDKContext polarisContext, CircuitBreakAPI circuitBreakAPI) {
return new ExceptionCircuitBreakerReporter(properties, polarisContext, circuitBreakAPI);
}
@Bean
@ConditionalOnMissingBean(ReactiveCircuitBreakerFactory.class)
public ReactiveCircuitBreakerFactory polarisReactiveCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) {

@ -0,0 +1,97 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.circuitbreaker.reporter;
import java.util.Optional;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
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.EnhancedRequestContext;
import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.core.Ordered;
public class ExceptionCircuitBreakerReporter extends AbstractPolarisReporterAdapter implements EnhancedPlugin {
private static final Logger LOG = LoggerFactory.getLogger(ExceptionCircuitBreakerReporter.class);
private final CircuitBreakAPI circuitBreakAPI;
public ExceptionCircuitBreakerReporter(RpcEnhancementReporterProperties reportProperties,
SDKContext context,
CircuitBreakAPI circuitBreakAPI) {
super(reportProperties, context);
this.circuitBreakAPI = circuitBreakAPI;
}
@Override
public String getName() {
return ExceptionCircuitBreakerReporter.class.getName();
}
@Override
public EnhancedPluginType getType() {
return EnhancedPluginType.EXCEPTION;
}
@Override
public void run(EnhancedPluginContext context) throws Throwable {
if (!super.reportProperties.isEnabled()) {
return;
}
EnhancedRequestContext request = context.getRequest();
ServiceInstance serviceInstance = Optional.ofNullable(context.getServiceInstance()).orElse(new DefaultServiceInstance());
ResourceStat resourceStat = createInstanceResourceStat(
serviceInstance.getServiceId(),
serviceInstance.getHost(),
serviceInstance.getPort(),
request.getUrl(),
null,
context.getDelay(),
context.getThrowable()
);
LOG.debug("Will report CircuitBreaker ResourceStat of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.",
resourceStat.getRetStatus().name(), request.getHttpMethod().name(), request.getUrl().getPath(), context.getThrowable().getMessage(), context.getDelay());
circuitBreakAPI.report(resourceStat);
}
@Override
public void handlerThrowable(EnhancedPluginContext context, Throwable throwable) {
LOG.error("ExceptionCircuitBreakerReporter runs failed. context=[{}].",
context, throwable);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 2;
}
}

@ -0,0 +1,99 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.circuitbreaker.reporter;
import java.util.Optional;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
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.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter;
import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.core.Ordered;
public class SuccessCircuitBreakerReporter extends AbstractPolarisReporterAdapter implements EnhancedPlugin {
private static final Logger LOG = LoggerFactory.getLogger(SuccessPolarisReporter.class);
private final CircuitBreakAPI circuitBreakAPI;
public SuccessCircuitBreakerReporter(RpcEnhancementReporterProperties reportProperties,
SDKContext context,
CircuitBreakAPI circuitBreakAPI) {
super(reportProperties, context);
this.circuitBreakAPI = circuitBreakAPI;
}
@Override
public String getName() {
return SuccessCircuitBreakerReporter.class.getName();
}
@Override
public EnhancedPluginType getType() {
return EnhancedPluginType.POST;
}
@Override
public void run(EnhancedPluginContext context) throws Throwable {
if (!super.reportProperties.isEnabled()) {
return;
}
EnhancedRequestContext request = context.getRequest();
EnhancedResponseContext response = context.getResponse();
ServiceInstance serviceInstance = Optional.ofNullable(context.getServiceInstance()).orElse(new DefaultServiceInstance());
ResourceStat resourceStat = createInstanceResourceStat(
serviceInstance.getServiceId(),
serviceInstance.getHost(),
serviceInstance.getPort(),
request.getUrl(),
response.getHttpStatus(),
context.getDelay(),
null
);
LOG.debug("Will report CircuitBreaker ResourceStat of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.",
resourceStat.getRetStatus().name(), request.getHttpMethod().name(), request.getUrl().getPath(), response.getHttpStatus(), context.getDelay());
circuitBreakAPI.report(resourceStat);
}
@Override
public void handlerThrowable(EnhancedPluginContext context, Throwable throwable) {
LOG.error("SuccessCircuitBreakerReporter runs failed. context=[{}].",
context, throwable);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 2;
}
}

@ -0,0 +1,145 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.circuitbreaker.reporter;
import java.net.URI;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
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.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* ExceptionCircuitBreakerReporterTest.
*
* @author sean yu
*/
@ExtendWith(MockitoExtension.class)
public class ExceptionCircuitBreakerReporterTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@Mock
private RpcEnhancementReporterProperties reporterProperties;
@Mock
private SDKContext sdkContext;
@InjectMocks
private ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter;
@Mock
private CircuitBreakAPI circuitBreakAPI;
@BeforeAll
static void beforeAll() {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test");
}
@AfterAll
static void afterAll() {
mockedApplicationContextAwareUtils.close();
}
@BeforeEach
void setUp() {
MetadataContext.LOCAL_NAMESPACE = NAMESPACE_TEST;
MetadataContext.LOCAL_SERVICE = SERVICE_PROVIDER;
}
@Test
public void testGetName() {
assertThat(exceptionCircuitBreakerReporter.getName()).isEqualTo(ExceptionCircuitBreakerReporter.class.getName());
}
@Test
public void testType() {
assertThat(exceptionCircuitBreakerReporter.getType()).isEqualTo(EnhancedPluginType.EXCEPTION);
}
@Test
public void testRun() throws Throwable {
EnhancedPluginContext context = mock(EnhancedPluginContext.class);
// test not report
exceptionCircuitBreakerReporter.run(context);
verify(context, times(0)).getRequest();
doReturn(true).when(reporterProperties).isEnabled();
EnhancedPluginContext pluginContext = new EnhancedPluginContext();
EnhancedRequestContext request = EnhancedRequestContext.builder()
.httpMethod(HttpMethod.GET)
.url(URI.create("http://0.0.0.0/"))
.httpHeaders(new HttpHeaders())
.build();
EnhancedResponseContext response = EnhancedResponseContext.builder()
.httpStatus(200)
.build();
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
serviceInstance.setServiceId(SERVICE_PROVIDER);
pluginContext.setRequest(request);
pluginContext.setResponse(response);
pluginContext.setServiceInstance(serviceInstance);
pluginContext.setThrowable(new RuntimeException());
exceptionCircuitBreakerReporter.run(pluginContext);
exceptionCircuitBreakerReporter.getOrder();
exceptionCircuitBreakerReporter.getName();
exceptionCircuitBreakerReporter.getType();
}
@Test
public void testHandlerThrowable() {
// mock request
EnhancedRequestContext request = mock(EnhancedRequestContext.class);
// mock response
EnhancedResponseContext response = mock(EnhancedResponseContext.class);
EnhancedPluginContext context = new EnhancedPluginContext();
context.setRequest(request);
context.setResponse(response);
exceptionCircuitBreakerReporter.handlerThrowable(context, new RuntimeException("Mock exception."));
}
}

@ -0,0 +1,143 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.circuitbreaker.reporter;
import java.net.URI;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
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.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.http.HttpMethod;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* SuccessCircuitBreakerReporterTest.
*
* @author sean yu
*/
@ExtendWith(MockitoExtension.class)
public class SuccessCircuitBreakerReporterTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@Mock
private SDKContext sdkContext;
@Mock
private RpcEnhancementReporterProperties reporterProperties;
@InjectMocks
private SuccessCircuitBreakerReporter successCircuitBreakerReporter;
@Mock
private CircuitBreakAPI circuitBreakAPI;
@BeforeAll
static void beforeAll() {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test");
}
@AfterAll
static void afterAll() {
mockedApplicationContextAwareUtils.close();
}
@BeforeEach
void setUp() {
MetadataContext.LOCAL_NAMESPACE = NAMESPACE_TEST;
MetadataContext.LOCAL_SERVICE = SERVICE_PROVIDER;
}
@Test
public void testGetName() {
assertThat(successCircuitBreakerReporter.getName()).isEqualTo(SuccessCircuitBreakerReporter.class.getName());
}
@Test
public void testType() {
assertThat(successCircuitBreakerReporter.getType()).isEqualTo(EnhancedPluginType.POST);
}
@Test
public void testRun() throws Throwable {
EnhancedPluginContext context = mock(EnhancedPluginContext.class);
// test not report
successCircuitBreakerReporter.run(context);
verify(context, times(0)).getRequest();
doReturn(true).when(reporterProperties).isEnabled();
EnhancedPluginContext pluginContext = new EnhancedPluginContext();
EnhancedRequestContext request = EnhancedRequestContext.builder()
.httpMethod(HttpMethod.GET)
.url(URI.create("http://0.0.0.0/"))
.build();
EnhancedResponseContext response = EnhancedResponseContext.builder()
.httpStatus(200)
.build();
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
serviceInstance.setServiceId(SERVICE_PROVIDER);
pluginContext.setRequest(request);
pluginContext.setResponse(response);
pluginContext.setServiceInstance(serviceInstance);
successCircuitBreakerReporter.run(pluginContext);
successCircuitBreakerReporter.getOrder();
successCircuitBreakerReporter.getName();
successCircuitBreakerReporter.getType();
}
@Test
public void testHandlerThrowable() {
// mock request
EnhancedRequestContext request = mock(EnhancedRequestContext.class);
// mock response
EnhancedResponseContext response = mock(EnhancedResponseContext.class);
EnhancedPluginContext context = new EnhancedPluginContext();
context.setRequest(request);
context.setResponse(response);
successCircuitBreakerReporter.handlerThrowable(context, new RuntimeException("Mock exception."));
}
}

@ -12,7 +12,9 @@ spring:
enabled: true
rejectRequestTipsFilePath: reject-tips.html
maxQueuingTime: 500
stat:
enabled: true
port: 28083
management:
endpoints:
web:

@ -32,41 +32,6 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-circuitbreaker-factory</artifactId>
<exclusions>
<exclusion>
<groupId>com.tencent.polaris</groupId>
<artifactId>router-rule</artifactId>
</exclusion>
<exclusion>
<groupId>com.tencent.polaris</groupId>
<artifactId>router-nearby</artifactId>
</exclusion>
<exclusion>
<groupId>com.tencent.polaris</groupId>
<artifactId>router-metadata</artifactId>
</exclusion>
<exclusion>
<groupId>com.tencent.polaris</groupId>
<artifactId>router-canary</artifactId>
</exclusion>
<exclusion>
<groupId>com.tencent.polaris</groupId>
<artifactId>router-set</artifactId>
</exclusion>
<exclusion>
<groupId>com.tencent.polaris</groupId>
<artifactId>router-isolated</artifactId>
</exclusion>
<exclusion>
<groupId>com.tencent.polaris</groupId>
<artifactId>router-healthy</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Polaris dependencies end -->
<dependency>

@ -68,7 +68,6 @@ import static org.springframework.http.HttpStatus.VARIANT_ALSO_NEGOTIATES;
* @author <a href="mailto:iskp.me@gmail.com">Elve.Xu</a> 2022-07-11
*/
public abstract class AbstractPolarisReporterAdapter {
private static final Logger LOG = LoggerFactory.getLogger(AbstractPolarisReporterAdapter.class);
private static final List<HttpStatus> HTTP_STATUSES = toList(NOT_IMPLEMENTED, BAD_GATEWAY,
SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT, HTTP_VERSION_NOT_SUPPORTED, VARIANT_ALSO_NEGOTIATES,
@ -88,13 +87,6 @@ public abstract class AbstractPolarisReporterAdapter {
this.context = context;
}
public ServiceCallResult createServiceCallResult(
@Nullable String calleeServiceName, URI uri, HttpHeaders requestHeaders, @Nullable HttpHeaders responseHeaders,
@Nullable Integer statusCode, long delay, @Nullable Throwable exception) {
return createServiceCallResult(
calleeServiceName, uri.getHost(), uri.getPort(), uri, requestHeaders, responseHeaders, statusCode, delay, exception);
}
/**
* createServiceCallResult.
* @param calleeServiceName will pick up url host when null
@ -129,13 +121,6 @@ public abstract class AbstractPolarisReporterAdapter {
return resultRequest;
}
public ResourceStat createInstanceResourceStat(
@Nullable String calleeServiceName, URI uri,
@Nullable Integer statusCode, long delay, @Nullable Throwable exception) {
return createInstanceResourceStat(
calleeServiceName, uri.getHost(), uri.getPort(), uri, statusCode, delay, exception);
}
/**
* createInstanceResourceStat.
* @param calleeServiceName will pick up url host when null
@ -261,16 +246,18 @@ public abstract class AbstractPolarisReporterAdapter {
}
private String getLabels(HttpHeaders headers) {
Collection<String> labels = headers.get(RouterConstant.ROUTER_LABEL_HEADER);
if (CollectionUtils.isNotEmpty(labels) && labels.iterator().hasNext()) {
String label = labels.iterator().next();
try {
label = URLDecoder.decode(label, UTF_8);
}
catch (UnsupportedEncodingException e) {
LOG.error("unsupported charset exception " + UTF_8, e);
if (headers != null) {
Collection<String> labels = headers.get(RouterConstant.ROUTER_LABEL_HEADER);
if (CollectionUtils.isNotEmpty(labels) && labels.iterator().hasNext()) {
String label = labels.iterator().next();
try {
label = URLDecoder.decode(label, UTF_8);
}
catch (UnsupportedEncodingException e) {
LOG.error("unsupported charset exception " + UTF_8, e);
}
return RequestLabelUtils.convertLabel(label);
}
return RequestLabelUtils.convertLabel(label);
}
return null;
}

@ -22,20 +22,18 @@ import java.util.List;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.feign.DefaultEnhancedFeignPluginRunner;
import com.tencent.cloud.rpc.enhancement.feign.EnhancedFeignBeanPostProcessor;
import com.tencent.cloud.rpc.enhancement.feign.EnhancedFeignPluginRunner;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin;
import com.tencent.cloud.rpc.enhancement.feign.plugin.reporter.ExceptionPolarisReporter;
import com.tencent.cloud.rpc.enhancement.feign.plugin.reporter.SuccessPolarisReporter;
import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.ExceptionPolarisReporter;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter;
import com.tencent.cloud.rpc.enhancement.resttemplate.BlockingLoadBalancerClientAspect;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedPolarisRestTemplateReporter;
import com.tencent.cloud.rpc.enhancement.scg.EnhancedPolarisGatewayReporter;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplate;
import com.tencent.cloud.rpc.enhancement.scg.EnhancedGatewayGlobalFilter;
import com.tencent.cloud.rpc.enhancement.webclient.EnhancedWebClientReporter;
import com.tencent.cloud.rpc.enhancement.webclient.PolarisLoadBalancerClientRequestTransformer;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.circuitbreak.factory.CircuitBreakAPIFactory;
import com.tencent.polaris.client.api.SDKContext;
import org.springframework.beans.factory.SmartInitializingSingleton;
@ -69,9 +67,23 @@ import org.springframework.web.reactive.function.client.WebClient;
public class RpcEnhancementAutoConfiguration {
@Bean
@ConditionalOnMissingBean(CircuitBreakAPI.class)
public CircuitBreakAPI circuitBreakAPI(SDKContext polarisContext) {
return CircuitBreakAPIFactory.createCircuitBreakAPIByContext(polarisContext);
public EnhancedPluginRunner enhancedFeignPluginRunner(
@Autowired(required = false) List<EnhancedPlugin> enhancedPlugins) {
return new DefaultEnhancedPluginRunner(enhancedPlugins);
}
@Bean
public SuccessPolarisReporter successPolarisReporter(RpcEnhancementReporterProperties properties,
SDKContext context,
ConsumerAPI consumerAPI) {
return new SuccessPolarisReporter(properties, context, consumerAPI);
}
@Bean
public ExceptionPolarisReporter exceptionPolarisReporter(RpcEnhancementReporterProperties properties,
SDKContext context,
ConsumerAPI consumerAPI) {
return new ExceptionPolarisReporter(properties, context, consumerAPI);
}
/**
@ -87,35 +99,10 @@ public class RpcEnhancementAutoConfiguration {
protected static class PolarisFeignClientAutoConfiguration {
@Bean
public EnhancedFeignPluginRunner enhancedFeignPluginRunner(
@Autowired(required = false) List<EnhancedFeignPlugin> enhancedFeignPlugins) {
return new DefaultEnhancedFeignPluginRunner(enhancedFeignPlugins);
}
@Bean
public EnhancedFeignBeanPostProcessor polarisFeignBeanPostProcessor(@Lazy EnhancedFeignPluginRunner pluginRunner) {
public EnhancedFeignBeanPostProcessor polarisFeignBeanPostProcessor(@Lazy EnhancedPluginRunner pluginRunner) {
return new EnhancedFeignBeanPostProcessor(pluginRunner);
}
@Configuration
static class PolarisReporterConfig {
@Bean
public SuccessPolarisReporter successPolarisReporter(RpcEnhancementReporterProperties properties,
SDKContext context,
ConsumerAPI consumerAPI,
CircuitBreakAPI circuitBreakAPI) {
return new SuccessPolarisReporter(properties, context, consumerAPI, circuitBreakAPI);
}
@Bean
public ExceptionPolarisReporter exceptionPolarisReporter(RpcEnhancementReporterProperties properties,
SDKContext context,
ConsumerAPI consumerAPI,
CircuitBreakAPI circuitBreakAPI) {
return new ExceptionPolarisReporter(properties, context, consumerAPI, circuitBreakAPI);
}
}
}
/**
@ -133,15 +120,12 @@ public class RpcEnhancementAutoConfiguration {
private List<RestTemplate> restTemplates = Collections.emptyList();
@Bean
public EnhancedPolarisRestTemplateReporter enhancedPolarisRestTemplateReporter(RpcEnhancementReporterProperties properties,
SDKContext context,
ConsumerAPI consumerAPI,
CircuitBreakAPI circuitBreakAPI) {
return new EnhancedPolarisRestTemplateReporter(properties, context, consumerAPI, circuitBreakAPI);
public EnhancedRestTemplate enhancedPolarisRestTemplateReporter(@Lazy EnhancedPluginRunner pluginRunner) {
return new EnhancedRestTemplate(pluginRunner);
}
@Bean
public SmartInitializingSingleton setPolarisReporterForRestTemplate(EnhancedPolarisRestTemplateReporter reporter) {
public SmartInitializingSingleton setPolarisReporterForRestTemplate(EnhancedRestTemplate reporter) {
return () -> {
for (RestTemplate restTemplate : restTemplates) {
restTemplate.getInterceptors().add(reporter);
@ -155,6 +139,7 @@ public class RpcEnhancementAutoConfiguration {
public BlockingLoadBalancerClientAspect blockingLoadBalancerClientAspect() {
return new BlockingLoadBalancerClientAspect();
}
}
/**
@ -165,22 +150,12 @@ public class RpcEnhancementAutoConfiguration {
@ConditionalOnClass(name = "org.springframework.web.reactive.function.client.WebClient")
protected static class PolarisWebClientAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(name = "org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerClientRequestTransformer")
public PolarisLoadBalancerClientRequestTransformer polarisLoadBalancerClientRequestTransformer() {
return new PolarisLoadBalancerClientRequestTransformer();
}
@Autowired(required = false)
private List<WebClient.Builder> webClientBuilder = Collections.emptyList();
@Bean
public EnhancedWebClientReporter exchangeFilterFunction(RpcEnhancementReporterProperties properties,
SDKContext context,
ConsumerAPI consumerAPI,
CircuitBreakAPI circuitBreakAPI) {
return new EnhancedWebClientReporter(properties, context, consumerAPI, circuitBreakAPI);
public EnhancedWebClientReporter exchangeFilterFunction(@Lazy EnhancedPluginRunner pluginRunner) {
return new EnhancedWebClientReporter(pluginRunner);
}
@Bean
@ -189,6 +164,14 @@ public class RpcEnhancementAutoConfiguration {
webClient.filter(reporter);
});
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(name = "org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerClientRequestTransformer")
public PolarisLoadBalancerClientRequestTransformer polarisLoadBalancerClientRequestTransformer() {
return new PolarisLoadBalancerClientRequestTransformer();
}
}
/**
@ -202,12 +185,10 @@ public class RpcEnhancementAutoConfiguration {
@Bean
@ConditionalOnClass(name = "org.springframework.cloud.gateway.filter.GlobalFilter")
public EnhancedPolarisGatewayReporter enhancedPolarisGatewayReporter(RpcEnhancementReporterProperties properties,
SDKContext context,
ConsumerAPI consumerAPI,
CircuitBreakAPI circuitBreakAPI) {
return new EnhancedPolarisGatewayReporter(properties, context, consumerAPI, circuitBreakAPI);
public EnhancedGatewayGlobalFilter enhancedPolarisGatewayReporter(@Lazy EnhancedPluginRunner pluginRunner) {
return new EnhancedGatewayGlobalFilter(pluginRunner);
}
}
}

@ -17,6 +17,7 @@
package com.tencent.cloud.rpc.enhancement.feign;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import feign.Client;
import org.springframework.beans.BeansException;
@ -37,11 +38,11 @@ import org.springframework.lang.NonNull;
*/
public class EnhancedFeignBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private final EnhancedFeignPluginRunner pluginRunner;
private final EnhancedPluginRunner pluginRunner;
private BeanFactory factory;
public EnhancedFeignBeanPostProcessor(EnhancedFeignPluginRunner pluginRunner) {
public EnhancedFeignBeanPostProcessor(EnhancedPluginRunner pluginRunner) {
this.pluginRunner = pluginRunner;
}

@ -18,17 +18,26 @@
package com.tencent.cloud.rpc.enhancement.feign;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import feign.Client;
import feign.Request;
import feign.Request.Options;
import feign.Response;
import static com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType.EXCEPTION;
import static com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType.FINALLY;
import static com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType.POST;
import static com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType.PRE;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.EXCEPTION;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.FINALLY;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.POST;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.PRE;
import static feign.Util.checkNotNull;
/**
@ -40,40 +49,64 @@ public class EnhancedFeignClient implements Client {
private final Client delegate;
private final EnhancedFeignPluginRunner pluginRunner;
private final EnhancedPluginRunner pluginRunner;
public EnhancedFeignClient(Client target, EnhancedFeignPluginRunner pluginRunner) {
public EnhancedFeignClient(Client target, EnhancedPluginRunner pluginRunner) {
this.delegate = checkNotNull(target, "target");
this.pluginRunner = pluginRunner;
}
@Override
public Response execute(Request request, Options options) throws IOException {
EnhancedFeignContext enhancedFeignContext = new EnhancedFeignContext();
enhancedFeignContext.setRequest(request);
enhancedFeignContext.setOptions(options);
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
HttpHeaders requestHeaders = new HttpHeaders();
request.headers().forEach((s, strings) -> requestHeaders.addAll(s, new ArrayList<>(strings)));
URI url = URI.create(request.url());
EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpHeaders(requestHeaders)
.httpMethod(HttpMethod.resolve(request.httpMethod().name()))
.url(url)
.build();
enhancedPluginContext.setRequest(enhancedRequestContext);
// Run pre enhanced feign plugins.
pluginRunner.run(PRE, enhancedFeignContext);
// Run pre enhanced plugins.
pluginRunner.run(PRE, enhancedPluginContext);
long startMillis = System.currentTimeMillis();
try {
long startMillis = System.currentTimeMillis();
Response response = delegate.execute(request, options);
enhancedFeignContext.setDelay(System.currentTimeMillis() - startMillis);
enhancedFeignContext.setResponse(response);
enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
HttpHeaders responseHeaders = new HttpHeaders();
response.headers().forEach((s, strings) -> responseHeaders.addAll(s, new ArrayList<>(strings)));
EnhancedResponseContext enhancedResponseContext = EnhancedResponseContext.builder()
.httpStatus(response.status())
.httpHeaders(responseHeaders)
.build();
enhancedPluginContext.setResponse(enhancedResponseContext);
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
serviceInstance.setServiceId(request.requestTemplate().feignTarget().name());
serviceInstance.setHost(url.getHost());
serviceInstance.setPort(url.getPort());
enhancedPluginContext.setServiceInstance(serviceInstance);
// Run post enhanced feign plugins.
pluginRunner.run(POST, enhancedFeignContext);
// Run post enhanced plugins.
pluginRunner.run(POST, enhancedPluginContext);
return response;
}
catch (IOException origin) {
enhancedFeignContext.setException(origin);
enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
enhancedPluginContext.setThrowable(origin);
// Run exception enhanced feign plugins.
pluginRunner.run(EXCEPTION, enhancedFeignContext);
pluginRunner.run(EXCEPTION, enhancedPluginContext);
throw origin;
}
finally {
// Run finally enhanced feign plugins.
pluginRunner.run(FINALLY, enhancedFeignContext);
// Run finally enhanced plugins.
pluginRunner.run(FINALLY, enhancedPluginContext);
}
}
}

@ -1,79 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.feign.plugin;
import feign.Request;
import feign.Response;
/**
* Context used by EnhancedFeignPlugin.
*
* @author Haotian Zhang
*/
public class EnhancedFeignContext {
private Request request;
private Request.Options options;
private Response response;
private Exception exception;
private long delay;
public Request getRequest() {
return request;
}
public void setRequest(Request request) {
this.request = request;
}
public Request.Options getOptions() {
return options;
}
public void setOptions(Request.Options options) {
this.options = options;
}
public Response getResponse() {
return response;
}
public void setResponse(Response response) {
this.response = response;
}
public Exception getException() {
return exception;
}
public void setException(Exception exception) {
this.exception = exception;
}
public long getDelay() {
return delay;
}
public void setDelay(long delay) {
this.delay = delay;
}
}

@ -1,130 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.feign.plugin.reporter;
import java.net.URI;
import java.util.ArrayList;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat;
import com.tencent.polaris.api.rpc.ServiceCallResult;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext;
import feign.Request;
import feign.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
/**
* Polaris reporter when feign call fails.
*
* @author Haotian Zhang
*/
public class ExceptionPolarisReporter extends AbstractPolarisReporterAdapter implements EnhancedFeignPlugin {
private static final Logger LOG = LoggerFactory.getLogger(ExceptionPolarisReporter.class);
private final RpcEnhancementReporterProperties reporterProperties;
private final ConsumerAPI consumerAPI;
private final CircuitBreakAPI circuitBreakAPI;
public ExceptionPolarisReporter(RpcEnhancementReporterProperties reporterProperties,
SDKContext context,
ConsumerAPI consumerAPI,
CircuitBreakAPI circuitBreakAPI) {
super(reporterProperties, context);
this.reporterProperties = reporterProperties;
this.consumerAPI = consumerAPI;
this.circuitBreakAPI = circuitBreakAPI;
}
@Override
public String getName() {
return ExceptionPolarisReporter.class.getName();
}
@Override
public EnhancedFeignPluginType getType() {
return EnhancedFeignPluginType.EXCEPTION;
}
@Override
public void run(EnhancedFeignContext context) {
if (!reporterProperties.isEnabled()) {
return;
}
Request request = context.getRequest();
Response response = context.getResponse();
Exception exception = context.getException();
long delay = context.getDelay();
HttpHeaders requestHeaders = new HttpHeaders();
request.headers().forEach((s, strings) -> requestHeaders.addAll(s, new ArrayList<>(strings)));
HttpHeaders responseHeaders = new HttpHeaders();
Integer status = null;
if (response != null) {
response.headers().forEach((s, strings) -> responseHeaders.addAll(s, new ArrayList<>(strings)));
status = response.status();
}
ServiceCallResult resultRequest = createServiceCallResult(
request.requestTemplate().feignTarget().name(),
URI.create(request.url()),
requestHeaders,
responseHeaders,
status,
delay,
exception
);
LOG.debug("Will report result of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.",
resultRequest.getRetStatus().name(), request.httpMethod().name(), request.url(), status, delay);
consumerAPI.updateServiceCallResult(resultRequest);
ResourceStat resourceStat = createInstanceResourceStat(
request.requestTemplate().feignTarget().name(),
URI.create(request.url()),
status,
delay,
exception
);
circuitBreakAPI.report(resourceStat);
}
@Override
public void handlerThrowable(EnhancedFeignContext context, Throwable throwable) {
Request request = context.getRequest();
Response response = context.getResponse();
LOG.error("ExceptionPolarisReporter runs failed. Request=[{}]. Response=[{}].", request, response, throwable);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 1;
}
}

@ -1,126 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.feign.plugin.reporter;
import java.net.URI;
import java.util.ArrayList;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat;
import com.tencent.polaris.api.rpc.ServiceCallResult;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext;
import feign.Request;
import feign.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
/**
* Polaris reporter when feign call is successful.
*
* @author Haotian Zhang
*/
public class SuccessPolarisReporter extends AbstractPolarisReporterAdapter implements EnhancedFeignPlugin {
private static final Logger LOG = LoggerFactory.getLogger(SuccessPolarisReporter.class);
private final ConsumerAPI consumerAPI;
private final CircuitBreakAPI circuitBreakAPI;
public SuccessPolarisReporter(RpcEnhancementReporterProperties properties,
SDKContext context,
ConsumerAPI consumerAPI,
CircuitBreakAPI circuitBreakAPI) {
super(properties, context);
this.consumerAPI = consumerAPI;
this.circuitBreakAPI = circuitBreakAPI;
}
@Override
public String getName() {
return SuccessPolarisReporter.class.getName();
}
@Override
public EnhancedFeignPluginType getType() {
return EnhancedFeignPluginType.POST;
}
@Override
public void run(EnhancedFeignContext context) {
if (!reportProperties.isEnabled()) {
return;
}
Request request = context.getRequest();
Response response = context.getResponse();
long delay = context.getDelay();
HttpHeaders requestHeaders = new HttpHeaders();
request.headers().forEach((s, strings) -> requestHeaders.addAll(s, new ArrayList<>(strings)));
HttpHeaders responseHeaders = new HttpHeaders();
Integer status = null;
if (response != null) {
response.headers().forEach((s, strings) -> responseHeaders.addAll(s, new ArrayList<>(strings)));
status = response.status();
}
ServiceCallResult resultRequest = createServiceCallResult(
request.requestTemplate().feignTarget().name(),
URI.create(request.url()),
requestHeaders,
responseHeaders,
status,
delay,
null
);
LOG.debug("Will report result of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.",
resultRequest.getRetStatus().name(), request.httpMethod().name(), request.url(), status, delay);
consumerAPI.updateServiceCallResult(resultRequest);
ResourceStat resourceStat = createInstanceResourceStat(
request.requestTemplate().feignTarget().name(),
URI.create(request.url()),
status,
delay,
null
);
circuitBreakAPI.report(resourceStat);
}
@Override
public void handlerThrowable(EnhancedFeignContext context, Throwable throwable) {
Request request = context.getRequest();
Response response = context.getResponse();
LOG.error("SuccessPolarisReporter runs failed. Request=[{}]. Response=[{}].", request, response, throwable);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 1;
}
}

@ -16,16 +16,13 @@
*
*/
package com.tencent.cloud.rpc.enhancement.feign;
package com.tencent.cloud.rpc.enhancement.plugin;
import java.util.Comparator;
import java.util.List;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType;
import org.springframework.util.CollectionUtils;
@ -34,14 +31,14 @@ import org.springframework.util.CollectionUtils;
*
* @author Derek Yi 2022-08-16
*/
public class DefaultEnhancedFeignPluginRunner implements EnhancedFeignPluginRunner {
public class DefaultEnhancedPluginRunner implements EnhancedPluginRunner {
private final Multimap<String, EnhancedFeignPlugin> pluginMap = ArrayListMultimap.create();
private final Multimap<String, EnhancedPlugin> pluginMap = ArrayListMultimap.create();
public DefaultEnhancedFeignPluginRunner(List<EnhancedFeignPlugin> enhancedFeignPlugins) {
if (!CollectionUtils.isEmpty(enhancedFeignPlugins)) {
enhancedFeignPlugins.stream()
.sorted(Comparator.comparing(EnhancedFeignPlugin::getOrder))
public DefaultEnhancedPluginRunner(List<EnhancedPlugin> enhancedPlugins) {
if (!CollectionUtils.isEmpty(enhancedPlugins)) {
enhancedPlugins.stream()
.sorted(Comparator.comparing(EnhancedPlugin::getOrder))
.forEach(plugin -> pluginMap.put(plugin.getType().name(), plugin));
}
}
@ -53,8 +50,8 @@ public class DefaultEnhancedFeignPluginRunner implements EnhancedFeignPluginRunn
* @param context context in enhanced feign client.
*/
@Override
public void run(EnhancedFeignPluginType pluginType, EnhancedFeignContext context) {
for (EnhancedFeignPlugin plugin : pluginMap.get(pluginType.name())) {
public void run(EnhancedPluginType pluginType, EnhancedPluginContext context) {
for (EnhancedPlugin plugin : pluginMap.get(pluginType.name())) {
try {
plugin.run(context);
}

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.rpc.enhancement.feign.plugin;
package com.tencent.cloud.rpc.enhancement.plugin;
import org.springframework.core.Ordered;
@ -24,7 +24,7 @@ import org.springframework.core.Ordered;
*
* @author Haotian Zhang
*/
public interface EnhancedFeignPlugin extends Ordered {
public interface EnhancedPlugin extends Ordered {
/**
* Get name of plugin.
@ -38,9 +38,9 @@ public interface EnhancedFeignPlugin extends Ordered {
/**
* Get type of plugin.
*
* @return {@link EnhancedFeignPluginType}
* @return {@link EnhancedPluginType}
*/
EnhancedFeignPluginType getType();
EnhancedPluginType getType();
/**
* Run the plugin.
@ -48,15 +48,15 @@ public interface EnhancedFeignPlugin extends Ordered {
* @param context context in enhanced feign client.
* @throws Throwable throwable thrown from run method.
*/
void run(EnhancedFeignContext context) throws Throwable;
void run(EnhancedPluginContext context) throws Throwable;
/**
* Handler throwable from {@link EnhancedFeignPlugin#run(EnhancedFeignContext)}.
* Handler throwable from {@link EnhancedPlugin#run(EnhancedPluginContext)}.
*
* @param context context in enhanced feign client.
* @param throwable throwable thrown from run method.
*/
default void handlerThrowable(EnhancedFeignContext context, Throwable throwable) {
default void handlerThrowable(EnhancedPluginContext context, Throwable throwable) {
}
}

@ -0,0 +1,90 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.plugin;
import org.springframework.cloud.client.ServiceInstance;
/**
* Context used by EnhancedPlugin.
*
* @author Haotian Zhang
*/
public class EnhancedPluginContext {
private EnhancedRequestContext request;
private EnhancedResponseContext response;
private Throwable throwable;
private long delay;
private ServiceInstance serviceInstance;
public EnhancedRequestContext getRequest() {
return request;
}
public void setRequest(EnhancedRequestContext request) {
this.request = request;
}
public EnhancedResponseContext getResponse() {
return response;
}
public void setResponse(EnhancedResponseContext response) {
this.response = response;
}
public Throwable getThrowable() {
return throwable;
}
public void setThrowable(Throwable throwable) {
this.throwable = throwable;
}
public long getDelay() {
return delay;
}
public void setDelay(long delay) {
this.delay = delay;
}
public ServiceInstance getServiceInstance() {
return serviceInstance;
}
public void setServiceInstance(ServiceInstance serviceInstance) {
this.serviceInstance = serviceInstance;
}
@Override
public String toString() {
return "EnhancedPluginContext{" +
"request=" + request +
", response=" + response +
", throwable=" + throwable +
", delay=" + delay +
", serviceInstance=" + serviceInstance +
'}';
}
}

@ -16,17 +16,14 @@
*
*/
package com.tencent.cloud.rpc.enhancement.feign;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType;
package com.tencent.cloud.rpc.enhancement.plugin;
/**
* Plugin runner.
*
* @author Derek Yi 2022-08-16
*/
public interface EnhancedFeignPluginRunner {
public interface EnhancedPluginRunner {
/**
* run the plugin.
@ -34,5 +31,5 @@ public interface EnhancedFeignPluginRunner {
* @param pluginType type of plugin
* @param context context in enhanced feign client.
*/
void run(EnhancedFeignPluginType pluginType, EnhancedFeignContext context);
void run(EnhancedPluginType pluginType, EnhancedPluginContext context);
}

@ -15,14 +15,14 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.rpc.enhancement.feign.plugin;
package com.tencent.cloud.rpc.enhancement.plugin;
/**
* Type of EnhancedFeignPlugin.
* Type of EnhancedPlugin.
*
* @author Haotian Zhang
*/
public enum EnhancedFeignPluginType {
public enum EnhancedPluginType {
/**
* Pre feign plugin.

@ -0,0 +1,107 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.plugin;
import java.net.URI;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
/**
* EnhancedRequestContext.
*
* @author sean yu
*/
public class EnhancedRequestContext {
private HttpMethod httpMethod;
private HttpHeaders httpHeaders;
private URI url;
public HttpMethod getHttpMethod() {
return httpMethod;
}
public void setHttpMethod(HttpMethod httpMethod) {
this.httpMethod = httpMethod;
}
public HttpHeaders getHttpHeaders() {
return httpHeaders;
}
public void setHttpHeaders(HttpHeaders httpHeaders) {
this.httpHeaders = httpHeaders;
}
public URI getUrl() {
return url;
}
public void setUrl(URI url) {
this.url = url;
}
public static EnhancedContextRequestBuilder builder() {
return new EnhancedContextRequestBuilder();
}
@Override
public String toString() {
return "EnhancedRequestContext{" +
"httpMethod=" + httpMethod +
", httpHeaders=" + httpHeaders +
", url=" + url +
'}';
}
public static final class EnhancedContextRequestBuilder {
private HttpMethod httpMethod;
private HttpHeaders httpHeaders;
private URI url;
private EnhancedContextRequestBuilder() {
}
public EnhancedContextRequestBuilder httpMethod(HttpMethod httpMethod) {
this.httpMethod = httpMethod;
return this;
}
public EnhancedContextRequestBuilder httpHeaders(HttpHeaders httpHeaders) {
this.httpHeaders = httpHeaders;
return this;
}
public EnhancedContextRequestBuilder url(URI url) {
this.url = url;
return this;
}
public EnhancedRequestContext build() {
EnhancedRequestContext enhancedRequestContext = new EnhancedRequestContext();
enhancedRequestContext.httpMethod = this.httpMethod;
enhancedRequestContext.url = this.url;
enhancedRequestContext.httpHeaders = this.httpHeaders;
return enhancedRequestContext;
}
}
}

@ -0,0 +1,86 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.plugin;
import org.springframework.http.HttpHeaders;
/**
* EnhancedResponseContext.
*
* @author sean yu
*/
public class EnhancedResponseContext {
private Integer httpStatus;
private HttpHeaders httpHeaders;
public Integer getHttpStatus() {
return httpStatus;
}
public void setHttpStatus(Integer httpStatus) {
this.httpStatus = httpStatus;
}
public HttpHeaders getHttpHeaders() {
return httpHeaders;
}
public void setHttpHeaders(HttpHeaders httpHeaders) {
this.httpHeaders = httpHeaders;
}
public static EnhancedContextResponseBuilder builder() {
return new EnhancedContextResponseBuilder();
}
@Override
public String toString() {
return "EnhancedResponseContext{" +
"httpStatus=" + httpStatus +
", httpHeaders=" + httpHeaders +
'}';
}
public static final class EnhancedContextResponseBuilder {
private Integer httpStatus;
private HttpHeaders httpHeaders;
private EnhancedContextResponseBuilder() {
}
public EnhancedContextResponseBuilder httpStatus(Integer httpStatus) {
this.httpStatus = httpStatus;
return this;
}
public EnhancedContextResponseBuilder httpHeaders(HttpHeaders httpHeaders) {
this.httpHeaders = httpHeaders;
return this;
}
public EnhancedResponseContext build() {
EnhancedResponseContext enhancedResponseContext = new EnhancedResponseContext();
enhancedResponseContext.setHttpStatus(httpStatus);
enhancedResponseContext.setHttpHeaders(httpHeaders);
return enhancedResponseContext;
}
}
}

@ -0,0 +1,106 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.plugin.reporter;
import java.util.Optional;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
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.EnhancedRequestContext;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.api.rpc.ServiceCallResult;
import com.tencent.polaris.client.api.SDKContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.core.Ordered;
/**
* Polaris reporter when feign call fails.
*
* @author Haotian Zhang
*/
public class ExceptionPolarisReporter extends AbstractPolarisReporterAdapter implements EnhancedPlugin {
private static final Logger LOG = LoggerFactory.getLogger(ExceptionPolarisReporter.class);
private final ConsumerAPI consumerAPI;
public ExceptionPolarisReporter(RpcEnhancementReporterProperties reporterProperties,
SDKContext context,
ConsumerAPI consumerAPI) {
super(reporterProperties, context);
this.consumerAPI = consumerAPI;
}
@Override
public String getName() {
return ExceptionPolarisReporter.class.getName();
}
@Override
public EnhancedPluginType getType() {
return EnhancedPluginType.EXCEPTION;
}
@Override
public void run(EnhancedPluginContext context) {
if (!super.reportProperties.isEnabled()) {
return;
}
EnhancedRequestContext request = context.getRequest();
ServiceInstance serviceInstance = Optional.ofNullable(context.getServiceInstance()).orElse(new DefaultServiceInstance());
ServiceCallResult resultRequest = createServiceCallResult(
serviceInstance.getServiceId(),
serviceInstance.getHost(),
serviceInstance.getPort(),
request.getUrl(),
request.getHttpHeaders(),
null,
null,
context.getDelay(),
context.getThrowable()
);
LOG.debug("Will report ServiceCallResult of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.",
resultRequest.getRetStatus().name(), request.getHttpMethod().name(), request.getUrl().getPath(), context.getThrowable().getMessage(), context.getDelay());
consumerAPI.updateServiceCallResult(resultRequest);
}
@Override
public void handlerThrowable(EnhancedPluginContext context, Throwable throwable) {
LOG.error("ExceptionPolarisReporter runs failed. context=[{}].",
context, throwable);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 1;
}
}

@ -0,0 +1,106 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.plugin.reporter;
import java.util.Optional;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
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.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.api.rpc.ServiceCallResult;
import com.tencent.polaris.client.api.SDKContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.core.Ordered;
/**
* Polaris reporter when feign call is successful.
*
* @author Haotian Zhang
*/
public class SuccessPolarisReporter extends AbstractPolarisReporterAdapter implements EnhancedPlugin {
private static final Logger LOG = LoggerFactory.getLogger(SuccessPolarisReporter.class);
private final ConsumerAPI consumerAPI;
public SuccessPolarisReporter(RpcEnhancementReporterProperties properties,
SDKContext context,
ConsumerAPI consumerAPI) {
super(properties, context);
this.consumerAPI = consumerAPI;
}
@Override
public String getName() {
return SuccessPolarisReporter.class.getName();
}
@Override
public EnhancedPluginType getType() {
return EnhancedPluginType.POST;
}
@Override
public void run(EnhancedPluginContext context) {
if (!super.reportProperties.isEnabled()) {
return;
}
EnhancedRequestContext request = context.getRequest();
EnhancedResponseContext response = context.getResponse();
ServiceInstance serviceInstance = Optional.ofNullable(context.getServiceInstance()).orElse(new DefaultServiceInstance());
ServiceCallResult resultRequest = createServiceCallResult(
serviceInstance.getServiceId(),
serviceInstance.getHost(),
serviceInstance.getPort(),
request.getUrl(),
request.getHttpHeaders(),
response.getHttpHeaders(),
response.getHttpStatus(),
context.getDelay(),
null
);
LOG.debug("Will report ServiceCallResult of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.",
resultRequest.getRetStatus().name(), request.getHttpMethod().name(), request.getUrl().getPath(), response.getHttpStatus(), context.getDelay());
consumerAPI.updateServiceCallResult(resultRequest);
}
@Override
public void handlerThrowable(EnhancedPluginContext context, Throwable throwable) {
LOG.error("SuccessPolarisReporter runs failed. context=[{}].",
context, throwable);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 1;
}
}

@ -1,131 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.resttemplate;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.Map;
import com.tencent.cloud.common.constant.HeaderConstant;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat;
import com.tencent.polaris.api.rpc.ServiceCallResult;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
/**
* EnhancedPolarisRestTemplateReporter.
*
* @author sean yu
*/
public class EnhancedPolarisRestTemplateReporter extends AbstractPolarisReporterAdapter implements ClientHttpRequestInterceptor {
private static final Logger LOG = LoggerFactory.getLogger(EnhancedPolarisRestTemplateReporter.class);
private final ConsumerAPI consumerAPI;
private final CircuitBreakAPI circuitBreakAPI;
/**
* Constructor With {@link RpcEnhancementReporterProperties} .
*
* @param reportProperties instance of {@link RpcEnhancementReporterProperties}.
*/
public EnhancedPolarisRestTemplateReporter(RpcEnhancementReporterProperties reportProperties,
SDKContext context,
ConsumerAPI consumerAPI,
CircuitBreakAPI circuitBreakAPI) {
super(reportProperties, context);
this.consumerAPI = consumerAPI;
this.circuitBreakAPI = circuitBreakAPI;
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
if (!reportProperties.isEnabled()) {
return execution.execute(request, body);
}
long startTime = System.currentTimeMillis();
ClientHttpResponse response = null;
IOException ex = null;
try {
response = execution.execute(request, body);
}
catch (SocketTimeoutException e) {
ex = e;
}
HttpHeaders requestHeaders = request.getHeaders();
HttpHeaders responseHeaders = null;
Integer status = null;
if (response != null) {
responseHeaders = response.getHeaders();
status = response.getRawStatusCode();
}
Map<String, String> loadBalancerContext = MetadataContextHolder.get().getLoadbalancerMetadata();
String targetHost = loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_INSTANCE_HOST);
Integer targetPort = loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_INSTANCE_PORT) != null ? Integer.valueOf(loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_INSTANCE_PORT)) : null;
long delay = System.currentTimeMillis() - startTime;
ServiceCallResult resultRequest = createServiceCallResult(
request.getURI().getHost(),
targetHost,
targetPort,
request.getURI(),
requestHeaders,
responseHeaders,
status,
delay,
ex
);
LOG.debug("Will report result of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.",
resultRequest.getRetStatus().name(), request.getMethod(), request.getURI().getPath(), status, delay);
consumerAPI.updateServiceCallResult(resultRequest);
ResourceStat resourceStat = createInstanceResourceStat(
request.getURI().getHost(),
targetHost,
targetPort,
request.getURI(),
status,
delay,
ex
);
circuitBreakAPI.report(resourceStat);
if (ex != null) {
throw ex;
}
return response;
}
}

@ -0,0 +1,105 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.resttemplate;
import java.io.IOException;
import java.util.Map;
import com.tencent.cloud.common.constant.HeaderConstant;
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.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.EXCEPTION;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.FINALLY;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.POST;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.PRE;
/**
* EnhancedRestTemplate.
*
* @author sean yu
*/
public class EnhancedRestTemplate implements ClientHttpRequestInterceptor {
private final EnhancedPluginRunner pluginRunner;
public EnhancedRestTemplate(EnhancedPluginRunner pluginRunner) {
this.pluginRunner = pluginRunner;
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpHeaders(request.getHeaders())
.httpMethod(request.getMethod())
.url(request.getURI())
.build();
enhancedPluginContext.setRequest(enhancedRequestContext);
// Run pre enhanced plugins.
pluginRunner.run(PRE, enhancedPluginContext);
long startMillis = System.currentTimeMillis();
try {
ClientHttpResponse response = execution.execute(request, body);
enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
EnhancedResponseContext enhancedResponseContext = EnhancedResponseContext.builder()
.httpStatus(response.getRawStatusCode())
.httpHeaders(response.getHeaders())
.build();
enhancedPluginContext.setResponse(enhancedResponseContext);
Map<String, String> loadBalancerContext = MetadataContextHolder.get().getLoadbalancerMetadata();
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
serviceInstance.setServiceId(request.getURI().getHost());
serviceInstance.setHost(loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_INSTANCE_HOST));
if (loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_INSTANCE_PORT) != null) {
serviceInstance.setPort(Integer.parseInt(loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_INSTANCE_PORT)));
}
enhancedPluginContext.setServiceInstance(serviceInstance);
// Run post enhanced plugins.
pluginRunner.run(POST, enhancedPluginContext);
return response;
}
catch (IOException e) {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
enhancedPluginContext.setThrowable(e);
// Run exception enhanced plugins.
pluginRunner.run(EXCEPTION, enhancedPluginContext);
throw e;
}
finally {
// Run finally enhanced plugins.
pluginRunner.run(FINALLY, enhancedPluginContext);
}
}
}

@ -0,0 +1,111 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.scg;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import reactor.core.publisher.Mono;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.EXCEPTION;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.FINALLY;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.POST;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.PRE;
import static org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter.ROUTE_TO_URL_FILTER_ORDER;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_LOADBALANCER_RESPONSE_ATTR;
/**
* EnhancedGatewayGlobalFilter.
*
* @author sean yu
*/
public class EnhancedGatewayGlobalFilter implements GlobalFilter, Ordered {
private final EnhancedPluginRunner pluginRunner;
public EnhancedGatewayGlobalFilter(EnhancedPluginRunner pluginRunner) {
this.pluginRunner = pluginRunner;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpHeaders(exchange.getRequest().getHeaders())
.httpMethod(exchange.getRequest().getMethod())
.url(exchange.getRequest().getURI())
.build();
enhancedPluginContext.setRequest(enhancedRequestContext);
// Run pre enhanced plugins.
pluginRunner.run(PRE, enhancedPluginContext);
long startTime = System.currentTimeMillis();
return chain.filter(exchange)
.doOnSuccess(v -> {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startTime);
EnhancedResponseContext enhancedResponseContext = EnhancedResponseContext.builder()
.httpStatus(exchange.getResponse().getRawStatusCode())
.httpHeaders(exchange.getResponse().getHeaders())
.build();
enhancedPluginContext.setResponse(enhancedResponseContext);
Response<ServiceInstance> serviceInstanceResponse = exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR);
if (serviceInstanceResponse != null && serviceInstanceResponse.hasServer()) {
ServiceInstance instance = serviceInstanceResponse.getServer();
enhancedPluginContext.setServiceInstance(instance);
}
// Run post enhanced plugins.
pluginRunner.run(POST, enhancedPluginContext);
})
.doOnError(t -> {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startTime);
enhancedPluginContext.setThrowable(t);
Response<ServiceInstance> serviceInstanceResponse = exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR);
if (serviceInstanceResponse != null && serviceInstanceResponse.hasServer()) {
ServiceInstance instance = serviceInstanceResponse.getServer();
enhancedPluginContext.setServiceInstance(instance);
}
// Run exception enhanced plugins.
pluginRunner.run(EXCEPTION, enhancedPluginContext);
})
.doFinally(v -> {
// Run finally enhanced plugins.
pluginRunner.run(FINALLY, enhancedPluginContext);
});
}
@Override
public int getOrder() {
return ROUTE_TO_URL_FILTER_ORDER + 1;
}
}

@ -1,129 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.scg;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat;
import com.tencent.polaris.api.rpc.ServiceCallResult;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import static org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter.ROUTE_TO_URL_FILTER_ORDER;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_LOADBALANCER_RESPONSE_ATTR;
/**
* EnhancedPolarisGatewayReporter.
*
* @author sean yu
*/
public class EnhancedPolarisGatewayReporter extends AbstractPolarisReporterAdapter implements GlobalFilter, Ordered {
private static final Logger LOG = LoggerFactory.getLogger(EnhancedPolarisGatewayReporter.class);
private final ConsumerAPI consumerAPI;
private final CircuitBreakAPI circuitBreakAPI;
/**
* Constructor With {@link RpcEnhancementReporterProperties} .
*
* @param reportProperties instance of {@link RpcEnhancementReporterProperties}.
*/
public EnhancedPolarisGatewayReporter(RpcEnhancementReporterProperties reportProperties,
SDKContext context,
ConsumerAPI consumerAPI,
CircuitBreakAPI circuitBreakAPI) {
super(reportProperties, context);
this.consumerAPI = consumerAPI;
this.circuitBreakAPI = circuitBreakAPI;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if (!reportProperties.isEnabled()) {
return chain.filter(exchange);
}
long startTime = System.currentTimeMillis();
return chain.filter(exchange)
.doOnSuccess(v -> instrumentResponse(exchange, null, startTime))
.doOnError(t -> instrumentResponse(exchange, t, startTime));
}
private void instrumentResponse(ServerWebExchange exchange, Throwable t, long startTime) {
ServerHttpResponse response = exchange.getResponse();
ServerHttpRequest request = exchange.getRequest();
long delay = System.currentTimeMillis() - startTime;
String serviceId = null;
String targetHost = null;
Integer targetPort = null;
Response<ServiceInstance> serviceInstanceResponse = exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR);
if (serviceInstanceResponse != null && serviceInstanceResponse.hasServer()) {
ServiceInstance instance = serviceInstanceResponse.getServer();
serviceId = instance.getServiceId();
targetHost = instance.getHost();
targetPort = instance.getPort();
}
ServiceCallResult resultRequest = createServiceCallResult(
serviceId,
targetHost,
targetPort,
request.getURI(),
request.getHeaders(),
response.getHeaders(),
response.getRawStatusCode(),
delay,
t
);
LOG.debug("Will report result of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.",
resultRequest.getRetStatus().name(), request.getMethod(), request.getURI().getPath(), response.getRawStatusCode(), delay);
consumerAPI.updateServiceCallResult(resultRequest);
ResourceStat resourceStat = createInstanceResourceStat(
serviceId,
targetHost,
targetPort,
request.getURI(),
response.getRawStatusCode(),
delay,
t
);
circuitBreakAPI.report(resourceStat);
}
@Override
public int getOrder() {
return ROUTE_TO_URL_FILTER_ORDER + 1;
}
}

@ -21,87 +21,84 @@ import java.util.Map;
import com.tencent.cloud.common.constant.HeaderConstant;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat;
import com.tencent.polaris.api.rpc.ServiceCallResult;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import reactor.core.publisher.Mono;
import org.springframework.http.HttpHeaders;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.ExchangeFunction;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.EXCEPTION;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.FINALLY;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.POST;
/**
* EnhancedWebClientReporter.
*
* @author sean yu
*/
public class EnhancedWebClientReporter extends AbstractPolarisReporterAdapter implements ExchangeFilterFunction {
private static final Logger LOG = LoggerFactory.getLogger(EnhancedWebClientReporter.class);
private final ConsumerAPI consumerAPI;
private final CircuitBreakAPI circuitBreakAPI;
public EnhancedWebClientReporter(RpcEnhancementReporterProperties reportProperties,
SDKContext context,
ConsumerAPI consumerAPI,
CircuitBreakAPI circuitBreakAPI) {
super(reportProperties, context);
this.consumerAPI = consumerAPI;
this.circuitBreakAPI = circuitBreakAPI;
public class EnhancedWebClientReporter implements ExchangeFilterFunction {
private final EnhancedPluginRunner pluginRunner;
public EnhancedWebClientReporter(EnhancedPluginRunner pluginRunner) {
this.pluginRunner = pluginRunner;
}
@Override
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
if (!reportProperties.isEnabled()) {
return next.exchange(request);
}
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpHeaders(request.headers())
.httpMethod(request.method())
.url(request.url())
.build();
enhancedPluginContext.setRequest(enhancedRequestContext);
long startTime = System.currentTimeMillis();
return next.exchange(request)
.doOnSuccess(response -> instrumentResponse(request, response, null, startTime))
.doOnError(t -> instrumentResponse(request, null, t, startTime));
}
.doOnSuccess(response -> {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startTime);
EnhancedResponseContext enhancedResponseContext = EnhancedResponseContext.builder()
.httpStatus(response.rawStatusCode())
.httpHeaders(response.headers().asHttpHeaders())
.build();
enhancedPluginContext.setResponse(enhancedResponseContext);
Map<String, String> loadBalancerContext = MetadataContextHolder.get().getLoadbalancerMetadata();
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
serviceInstance.setServiceId(loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_SERVICE_ID));
serviceInstance.setHost(request.url().getHost());
serviceInstance.setPort(request.url().getPort());
enhancedPluginContext.setServiceInstance(serviceInstance);
// Run post enhanced plugins.
pluginRunner.run(POST, enhancedPluginContext);
})
.doOnError(t -> {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startTime);
enhancedPluginContext.setThrowable(t);
Map<String, String> loadBalancerContext = MetadataContextHolder.get().getLoadbalancerMetadata();
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
serviceInstance.setServiceId(loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_SERVICE_ID));
serviceInstance.setHost(request.url().getHost());
serviceInstance.setPort(request.url().getPort());
enhancedPluginContext.setServiceInstance(serviceInstance);
private void instrumentResponse(ClientRequest request, ClientResponse response, Throwable t, long startTime) {
Map<String, String> loadBalancerContext = MetadataContextHolder.get().getLoadbalancerMetadata();
String serviceId = loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_SERVICE_ID);
long delay = System.currentTimeMillis() - startTime;
HttpHeaders requestHeaders = request.headers();
HttpHeaders responseHeaders = null;
Integer status = null;
if (response != null) {
responseHeaders = response.headers().asHttpHeaders();
status = response.rawStatusCode();
}
ServiceCallResult resultRequest = createServiceCallResult(
serviceId,
request.url(),
requestHeaders,
responseHeaders,
status,
delay,
t
);
LOG.debug("Will report result of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.",
resultRequest.getRetStatus().name(), request.method().name(), request.url().getPath(), status, delay);
consumerAPI.updateServiceCallResult(resultRequest);
ResourceStat resourceStat = createInstanceResourceStat(
serviceId,
request.url(),
status,
delay,
t
);
circuitBreakAPI.report(resourceStat);
// Run exception enhanced plugins.
pluginRunner.run(EXCEPTION, enhancedPluginContext);
})
.doFinally(v -> {
// Run finally enhanced plugins.
pluginRunner.run(FINALLY, enhancedPluginContext);
});
}
}

@ -106,6 +106,8 @@ public class AbstractPolarisReporterAdapterTest {
serviceCallResult = adapter.createServiceCallResult(
"test",
null,
null,
new URI("http://0.0.0.0/"),
requestHeaders,
new HttpHeaders(),
@ -117,6 +119,8 @@ public class AbstractPolarisReporterAdapterTest {
serviceCallResult = adapter.createServiceCallResult(
"test",
null,
null,
new URI("http://0.0.0.0/"),
requestHeaders,
new HttpHeaders(),
@ -128,6 +132,8 @@ public class AbstractPolarisReporterAdapterTest {
serviceCallResult = adapter.createServiceCallResult(
"test",
null,
null,
new URI("http://0.0.0.0/"),
requestHeaders,
null,
@ -161,6 +167,8 @@ public class AbstractPolarisReporterAdapterTest {
ResourceStat resourceStat;
resourceStat = adapter.createInstanceResourceStat("test",
null,
null,
new URI("http://0.0.0.0/"),
200,
0,
@ -169,6 +177,8 @@ public class AbstractPolarisReporterAdapterTest {
assertThat(resourceStat.getRetStatus()).isEqualTo(RetStatus.RetSuccess);
resourceStat = adapter.createInstanceResourceStat("test",
null,
null,
new URI("http://0.0.0.0/"),
null,
0,

@ -19,10 +19,10 @@ package com.tencent.cloud.rpc.enhancement.config;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.feign.EnhancedFeignBeanPostProcessor;
import com.tencent.cloud.rpc.enhancement.feign.EnhancedFeignPluginRunner;
import com.tencent.cloud.rpc.enhancement.feign.plugin.reporter.ExceptionPolarisReporter;
import com.tencent.cloud.rpc.enhancement.feign.plugin.reporter.SuccessPolarisReporter;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedPolarisRestTemplateReporter;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.ExceptionPolarisReporter;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplate;
import com.tencent.polaris.api.core.ConsumerAPI;
import org.junit.jupiter.api.Test;
@ -56,11 +56,11 @@ public class RpcEnhancementAutoConfigurationTest {
public void testDefaultInitialization() {
this.contextRunner.run(context -> {
assertThat(context).hasSingleBean(ConsumerAPI.class);
assertThat(context).hasSingleBean(EnhancedFeignPluginRunner.class);
assertThat(context).hasSingleBean(EnhancedPluginRunner.class);
assertThat(context).hasSingleBean(EnhancedFeignBeanPostProcessor.class);
assertThat(context).hasSingleBean(SuccessPolarisReporter.class);
assertThat(context).hasSingleBean(ExceptionPolarisReporter.class);
assertThat(context).hasSingleBean(EnhancedPolarisRestTemplateReporter.class);
assertThat(context).hasSingleBean(EnhancedRestTemplate.class);
assertThat(context).hasSingleBean(RestTemplate.class);
});
}

@ -40,7 +40,8 @@ import static org.springframework.http.HttpStatus.Series.SERVER_ERROR;
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = RpcEnhancementReporterPropertiesTest.TestApplication.class, properties = {
"spring.application.name=test",
"spring.cloud.gateway.enabled=false"
"spring.cloud.gateway.enabled=false",
"spring.cloud.tencent.rpc-enhancement.reporter=true"
})
@ActiveProfiles("test")
public class RpcEnhancementReporterPropertiesTest {
@ -58,6 +59,7 @@ public class RpcEnhancementReporterPropertiesTest {
assertThat(rpcEnhancementReporterProperties.getStatuses()).isNotEmpty();
assertThat(rpcEnhancementReporterProperties.getStatuses().get(0)).isEqualTo(MULTIPLE_CHOICES);
assertThat(rpcEnhancementReporterProperties.getStatuses().get(1)).isEqualTo(MOVED_PERMANENTLY);
assertThat(rpcEnhancementReporterProperties.isEnabled()).isEqualTo(true);
}
@SpringBootApplication

@ -22,9 +22,10 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner;
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 feign.Client;
import feign.Request;
import feign.RequestTemplate;
@ -72,9 +73,9 @@ public class EnhancedFeignClientTest {
fail("Exception encountered.", e);
}
List<EnhancedFeignPlugin> enhancedFeignPlugins = getMockEnhancedFeignPlugins();
List<EnhancedPlugin> enhancedPlugins = getMockEnhancedFeignPlugins();
try {
new EnhancedFeignClient(mock(Client.class), new DefaultEnhancedFeignPluginRunner(enhancedFeignPlugins));
new EnhancedFeignClient(mock(Client.class), new DefaultEnhancedPluginRunner(enhancedPlugins));
}
catch (Throwable e) {
fail("Exception encountered.", e);
@ -103,7 +104,7 @@ public class EnhancedFeignClientTest {
RequestTemplate requestTemplate = new RequestTemplate();
requestTemplate.feignTarget(target);
EnhancedFeignClient polarisFeignClient = new EnhancedFeignClient(delegate, new DefaultEnhancedFeignPluginRunner(getMockEnhancedFeignPlugins()));
EnhancedFeignClient polarisFeignClient = new EnhancedFeignClient(delegate, new DefaultEnhancedPluginRunner(getMockEnhancedFeignPlugins()));
// 200
Response response = polarisFeignClient.execute(Request.create(Request.HttpMethod.GET, "http://localhost:8080/test",
@ -127,22 +128,22 @@ public class EnhancedFeignClientTest {
}
}
private List<EnhancedFeignPlugin> getMockEnhancedFeignPlugins() {
List<EnhancedFeignPlugin> enhancedFeignPlugins = new ArrayList<>();
private List<EnhancedPlugin> getMockEnhancedFeignPlugins() {
List<EnhancedPlugin> enhancedPlugins = new ArrayList<>();
enhancedFeignPlugins.add(new EnhancedFeignPlugin() {
enhancedPlugins.add(new EnhancedPlugin() {
@Override
public EnhancedFeignPluginType getType() {
return EnhancedFeignPluginType.PRE;
public EnhancedPluginType getType() {
return EnhancedPluginType.PRE;
}
@Override
public void run(EnhancedFeignContext context) {
public void run(EnhancedPluginContext context) {
}
@Override
public void handlerThrowable(EnhancedFeignContext context, Throwable throwable) {
public void handlerThrowable(EnhancedPluginContext context, Throwable throwable) {
}
@ -152,19 +153,19 @@ public class EnhancedFeignClientTest {
}
});
enhancedFeignPlugins.add(new EnhancedFeignPlugin() {
enhancedPlugins.add(new EnhancedPlugin() {
@Override
public EnhancedFeignPluginType getType() {
return EnhancedFeignPluginType.POST;
public EnhancedPluginType getType() {
return EnhancedPluginType.POST;
}
@Override
public void run(EnhancedFeignContext context) {
public void run(EnhancedPluginContext context) {
}
@Override
public void handlerThrowable(EnhancedFeignContext context, Throwable throwable) {
public void handlerThrowable(EnhancedPluginContext context, Throwable throwable) {
}
@ -174,19 +175,19 @@ public class EnhancedFeignClientTest {
}
});
enhancedFeignPlugins.add(new EnhancedFeignPlugin() {
enhancedPlugins.add(new EnhancedPlugin() {
@Override
public EnhancedFeignPluginType getType() {
return EnhancedFeignPluginType.EXCEPTION;
public EnhancedPluginType getType() {
return EnhancedPluginType.EXCEPTION;
}
@Override
public void run(EnhancedFeignContext context) {
public void run(EnhancedPluginContext context) {
}
@Override
public void handlerThrowable(EnhancedFeignContext context, Throwable throwable) {
public void handlerThrowable(EnhancedPluginContext context, Throwable throwable) {
}
@ -196,19 +197,19 @@ public class EnhancedFeignClientTest {
}
});
enhancedFeignPlugins.add(new EnhancedFeignPlugin() {
enhancedPlugins.add(new EnhancedPlugin() {
@Override
public EnhancedFeignPluginType getType() {
return EnhancedFeignPluginType.FINALLY;
public EnhancedPluginType getType() {
return EnhancedPluginType.FINALLY;
}
@Override
public void run(EnhancedFeignContext context) {
public void run(EnhancedPluginContext context) {
}
@Override
public void handlerThrowable(EnhancedFeignContext context, Throwable throwable) {
public void handlerThrowable(EnhancedPluginContext context, Throwable throwable) {
}
@ -218,7 +219,7 @@ public class EnhancedFeignClientTest {
}
});
return enhancedFeignPlugins;
return enhancedPlugins;
}

@ -1,46 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.feign.plugin;
import feign.Request;
import feign.Response;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Test for {@link EnhancedFeignContext}.
*
* @author Haotian Zhang
*/
public class EnhancedFeignContextTest {
@Test
public void testGetAndSet() {
EnhancedFeignContext enhancedFeignContext = new EnhancedFeignContext();
enhancedFeignContext.setRequest(mock(Request.class));
enhancedFeignContext.setOptions(mock(Request.Options.class));
enhancedFeignContext.setResponse(mock(Response.class));
enhancedFeignContext.setException(mock(Exception.class));
assertThat(enhancedFeignContext.getRequest()).isNotNull();
assertThat(enhancedFeignContext.getOptions()).isNotNull();
assertThat(enhancedFeignContext.getResponse()).isNotNull();
assertThat(enhancedFeignContext.getException()).isNotNull();
}
}

@ -0,0 +1,134 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.plugin;
import java.net.URI;
import java.util.Arrays;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.ExceptionPolarisReporter;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.client.api.SDKContext;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
/**
* Test for {@link EnhancedPluginContext}.
*
* @author Haotian Zhang
*/
@ExtendWith(MockitoExtension.class)
public class EnhancedPluginContextTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@Mock
private RpcEnhancementReporterProperties reporterProperties;
@Mock
private SDKContext sdkContext;
@Mock
private ConsumerAPI consumerAPI;
@BeforeAll
static void beforeAll() {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test");
}
@AfterAll
static void afterAll() {
mockedApplicationContextAwareUtils.close();
}
@BeforeEach
void setUp() {
MetadataContext.LOCAL_NAMESPACE = NAMESPACE_TEST;
MetadataContext.LOCAL_SERVICE = SERVICE_PROVIDER;
}
@Test
public void testGetAndSet() throws Throwable {
EnhancedRequestContext requestContext = new EnhancedRequestContext();
requestContext.setHttpHeaders(new HttpHeaders());
requestContext.setUrl(new URI("/"));
requestContext.setHttpMethod(HttpMethod.GET);
EnhancedRequestContext requestContext1 = EnhancedRequestContext.builder()
.httpHeaders(requestContext.getHttpHeaders())
.url(requestContext.getUrl())
.httpMethod(requestContext.getHttpMethod())
.build();
assertThat(requestContext1.getUrl()).isEqualTo(requestContext.getUrl());
EnhancedResponseContext responseContext = new EnhancedResponseContext();
responseContext.setHttpStatus(200);
responseContext.setHttpHeaders(new HttpHeaders());
EnhancedResponseContext responseContext1 = EnhancedResponseContext.builder()
.httpStatus(responseContext.getHttpStatus())
.httpHeaders(responseContext.getHttpHeaders())
.build();
assertThat(responseContext1.getHttpStatus()).isEqualTo(responseContext.getHttpStatus());
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
enhancedPluginContext.setRequest(requestContext);
enhancedPluginContext.setResponse(responseContext);
enhancedPluginContext.setServiceInstance(new DefaultServiceInstance());
enhancedPluginContext.setThrowable(mock(Exception.class));
enhancedPluginContext.setDelay(0);
assertThat(enhancedPluginContext.getRequest()).isNotNull();
assertThat(enhancedPluginContext.getResponse()).isNotNull();
assertThat(enhancedPluginContext.getServiceInstance()).isNotNull();
assertThat(enhancedPluginContext.getThrowable()).isNotNull();
assertThat(enhancedPluginContext.getDelay()).isNotNull();
EnhancedPlugin enhancedPlugin = new SuccessPolarisReporter(reporterProperties, sdkContext, consumerAPI);
EnhancedPlugin enhancedPlugin1 = new ExceptionPolarisReporter(reporterProperties, sdkContext, consumerAPI);
EnhancedPluginRunner enhancedPluginRunner = new DefaultEnhancedPluginRunner(Arrays.asList(enhancedPlugin, enhancedPlugin1));
enhancedPluginRunner.run(EnhancedPluginType.POST, enhancedPluginContext);
EnhancedPlugin enhancedPlugin2 = mock(EnhancedPlugin.class);
doThrow(new RuntimeException()).when(enhancedPlugin2).run(any());
doReturn(EnhancedPluginType.POST).when(enhancedPlugin2).getType();
enhancedPluginRunner = new DefaultEnhancedPluginRunner(Arrays.asList(enhancedPlugin2));
enhancedPluginRunner.run(EnhancedPluginType.POST, enhancedPluginContext);
}
}

@ -15,25 +15,19 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.rpc.enhancement.feign.plugin.reporter;
package com.tencent.cloud.rpc.enhancement.plugin;
import java.util.HashMap;
import java.net.URI;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.ExceptionPolarisReporter;
import com.tencent.polaris.api.config.Configuration;
import com.tencent.polaris.api.config.global.APIConfig;
import com.tencent.polaris.api.config.global.GlobalConfig;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext;
import feign.Request;
import feign.RequestTemplate;
import feign.Response;
import feign.Target;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
@ -45,6 +39,10 @@ import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
@ -67,12 +65,10 @@ public class ExceptionPolarisReporterTest {
private RpcEnhancementReporterProperties reporterProperties;
@Mock
private SDKContext sdkContext;
@Mock
private ConsumerAPI consumerAPI;
@Mock
private CircuitBreakAPI circuitBreakAPI;
@InjectMocks
private ExceptionPolarisReporter exceptionPolarisReporter;
@Mock
private ConsumerAPI consumerAPI;
@BeforeAll
static void beforeAll() {
@ -99,20 +95,17 @@ public class ExceptionPolarisReporterTest {
@Test
public void testType() {
assertThat(exceptionPolarisReporter.getType()).isEqualTo(EnhancedFeignPluginType.EXCEPTION);
assertThat(exceptionPolarisReporter.getType()).isEqualTo(EnhancedPluginType.EXCEPTION);
}
@Test
public void testRun() {
EnhancedFeignContext context = mock(EnhancedFeignContext.class);
EnhancedPluginContext context = mock(EnhancedPluginContext.class);
// test not report
exceptionPolarisReporter.run(context);
verify(context, times(0)).getRequest();
doReturn(true).when(reporterProperties).isEnabled();
// mock target
Target<?> target = mock(Target.class);
doReturn(SERVICE_PROVIDER).when(target).name();
APIConfig apiConfig = mock(APIConfig.class);
doReturn("0.0.0.0").when(apiConfig).getBindIP();
@ -125,29 +118,37 @@ public class ExceptionPolarisReporterTest {
doReturn(configuration).when(sdkContext).getConfig();
// mock RequestTemplate.class
RequestTemplate requestTemplate = new RequestTemplate();
requestTemplate.feignTarget(target);
EnhancedFeignContext feignContext = new EnhancedFeignContext();
Request request = Request.create(Request.HttpMethod.GET, "http://0.0.0.0/", new HashMap<>(), null, null, requestTemplate);
Response response = Response.builder()
.request(request)
EnhancedPluginContext pluginContext = new EnhancedPluginContext();
EnhancedRequestContext request = EnhancedRequestContext.builder()
.httpMethod(HttpMethod.GET)
.url(URI.create("http://0.0.0.0/"))
.httpHeaders(new HttpHeaders())
.build();
EnhancedResponseContext response = EnhancedResponseContext.builder()
.httpStatus(200)
.build();
feignContext.setRequest(request);
feignContext.setResponse(response);
exceptionPolarisReporter.run(feignContext);
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
serviceInstance.setServiceId(SERVICE_PROVIDER);
pluginContext.setRequest(request);
pluginContext.setResponse(response);
pluginContext.setServiceInstance(serviceInstance);
pluginContext.setThrowable(new RuntimeException());
exceptionPolarisReporter.run(pluginContext);
exceptionPolarisReporter.getOrder();
exceptionPolarisReporter.getName();
exceptionPolarisReporter.getType();
}
@Test
public void testHandlerThrowable() {
// mock request
Request request = mock(Request.class);
EnhancedRequestContext request = mock(EnhancedRequestContext.class);
// mock response
Response response = mock(Response.class);
EnhancedResponseContext response = mock(EnhancedResponseContext.class);
EnhancedFeignContext context = new EnhancedFeignContext();
EnhancedPluginContext context = new EnhancedPluginContext();
context.setRequest(request);
context.setResponse(response);
exceptionPolarisReporter.handlerThrowable(context, new RuntimeException("Mock exception."));

@ -15,25 +15,19 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.rpc.enhancement.feign.plugin.reporter;
package com.tencent.cloud.rpc.enhancement.plugin;
import java.util.HashMap;
import java.net.URI;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter;
import com.tencent.polaris.api.config.Configuration;
import com.tencent.polaris.api.config.global.APIConfig;
import com.tencent.polaris.api.config.global.GlobalConfig;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext;
import feign.Request;
import feign.RequestTemplate;
import feign.Response;
import feign.Target;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
@ -45,6 +39,9 @@ import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.http.HttpMethod;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
@ -65,13 +62,11 @@ public class SuccessPolarisReporterTest {
@Mock
private SDKContext sdkContext;
@Mock
private ConsumerAPI consumerAPI;
@Mock
private CircuitBreakAPI circuitBreakAPI;
@Mock
private RpcEnhancementReporterProperties reporterProperties;
@InjectMocks
private SuccessPolarisReporter successPolarisReporter;
@Mock
private ConsumerAPI consumerAPI;
@BeforeAll
static void beforeAll() {
@ -98,22 +93,18 @@ public class SuccessPolarisReporterTest {
@Test
public void testType() {
assertThat(successPolarisReporter.getType()).isEqualTo(EnhancedFeignPluginType.POST);
assertThat(successPolarisReporter.getType()).isEqualTo(EnhancedPluginType.POST);
}
@Test
public void testRun() {
EnhancedFeignContext context = mock(EnhancedFeignContext.class);
EnhancedPluginContext context = mock(EnhancedPluginContext.class);
// test not report
successPolarisReporter.run(context);
verify(context, times(0)).getRequest();
doReturn(true).when(reporterProperties).isEnabled();
// mock target
Target<?> target = mock(Target.class);
doReturn(SERVICE_PROVIDER).when(target).name();
APIConfig apiConfig = mock(APIConfig.class);
doReturn("0.0.0.0").when(apiConfig).getBindIP();
@ -125,29 +116,35 @@ public class SuccessPolarisReporterTest {
doReturn(configuration).when(sdkContext).getConfig();
// mock RequestTemplate.class
RequestTemplate requestTemplate = new RequestTemplate();
requestTemplate.feignTarget(target);
EnhancedFeignContext feignContext = new EnhancedFeignContext();
Request request = Request.create(Request.HttpMethod.GET, "http://0.0.0.0/", new HashMap<>(), null, null, requestTemplate);
Response response = Response.builder()
.request(request)
EnhancedPluginContext pluginContext = new EnhancedPluginContext();
EnhancedRequestContext request = EnhancedRequestContext.builder()
.httpMethod(HttpMethod.GET)
.url(URI.create("http://0.0.0.0/"))
.build();
EnhancedResponseContext response = EnhancedResponseContext.builder()
.httpStatus(200)
.build();
feignContext.setRequest(request);
feignContext.setResponse(response);
successPolarisReporter.run(feignContext);
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
serviceInstance.setServiceId(SERVICE_PROVIDER);
pluginContext.setRequest(request);
pluginContext.setResponse(response);
pluginContext.setServiceInstance(serviceInstance);
successPolarisReporter.run(pluginContext);
successPolarisReporter.getOrder();
successPolarisReporter.getName();
successPolarisReporter.getType();
}
@Test
public void testHandlerThrowable() {
// mock request
Request request = mock(Request.class);
EnhancedRequestContext request = mock(EnhancedRequestContext.class);
// mock response
Response response = mock(Response.class);
EnhancedResponseContext response = mock(EnhancedResponseContext.class);
EnhancedFeignContext context = new EnhancedFeignContext();
EnhancedPluginContext context = new EnhancedPluginContext();
context.setRequest(request);
context.setResponse(response);
successPolarisReporter.handlerThrowable(context, new RuntimeException("Mock exception."));

@ -21,17 +21,14 @@ import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.polaris.api.config.Configuration;
import com.tencent.polaris.api.config.global.APIConfig;
import com.tencent.polaris.api.config.global.GlobalConfig;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner;
import com.tencent.polaris.client.api.SDKContext;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
@ -60,7 +57,7 @@ import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
@ExtendWith(MockitoExtension.class)
public class EnhancedPolarisRestTemplateReporterTest {
public class EnhancedRestTemplateTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@Mock
@ -68,10 +65,6 @@ public class EnhancedPolarisRestTemplateReporterTest {
@Mock
private SDKContext sdkContext;
@Mock
private ConsumerAPI consumerAPI;
@Mock
private CircuitBreakAPI circuitBreakAPI;
@Mock
private ClientHttpRequestExecution mockClientHttpRequestExecution;
@Mock
private ClientHttpResponse mockClientHttpResponse;
@ -107,17 +100,6 @@ public class EnhancedPolarisRestTemplateReporterTest {
@Test
public void testRun() throws IOException, URISyntaxException {
APIConfig apiConfig = mock(APIConfig.class);
doReturn("0.0.0.0").when(apiConfig).getBindIP();
GlobalConfig globalConfig = mock(GlobalConfig.class);
doReturn(apiConfig).when(globalConfig).getAPI();
Configuration configuration = mock(Configuration.class);
doReturn(globalConfig).when(configuration).getGlobal();
doReturn(configuration).when(sdkContext).getConfig();
ClientHttpResponse actualResult;
final byte[] inputBody = null;
@ -127,11 +109,10 @@ public class EnhancedPolarisRestTemplateReporterTest {
doReturn(mockHttpHeaders).when(mockHttpRequest).getHeaders();
doReturn(mockClientHttpResponse).when(mockClientHttpRequestExecution).execute(mockHttpRequest, inputBody);
EnhancedPolarisRestTemplateReporter reporter = new EnhancedPolarisRestTemplateReporter(reporterProperties, sdkContext, consumerAPI, circuitBreakAPI);
EnhancedRestTemplate reporter = new EnhancedRestTemplate(new DefaultEnhancedPluginRunner(new ArrayList<>()));
actualResult = reporter.intercept(mockHttpRequest, inputBody, mockClientHttpRequestExecution);
assertThat(actualResult).isEqualTo(mockClientHttpResponse);
doReturn(true).when(reporterProperties).isEnabled();
actualResult = reporter.intercept(mockHttpRequest, inputBody, mockClientHttpRequestExecution);
assertThat(actualResult).isEqualTo(mockClientHttpResponse);

@ -19,17 +19,14 @@ package com.tencent.cloud.rpc.enhancement.scg;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.polaris.api.config.Configuration;
import com.tencent.polaris.api.config.global.APIConfig;
import com.tencent.polaris.api.config.global.GlobalConfig;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner;
import com.tencent.polaris.client.api.SDKContext;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
@ -54,13 +51,14 @@ import org.springframework.web.server.ServerWebExchange;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_LOADBALANCER_RESPONSE_ATTR;
@ExtendWith(MockitoExtension.class)
public class EnhancedPolarisGatewayReporterTest {
public class EnhancedGatewayGlobalFilterTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@Mock
@ -68,10 +66,6 @@ public class EnhancedPolarisGatewayReporterTest {
@Mock
private SDKContext sdkContext;
@Mock
private ConsumerAPI consumerAPI;
@Mock
private CircuitBreakAPI circuitBreakAPI;
@Mock
ServerWebExchange exchange;
@Mock
GatewayFilterChain chain;
@ -106,16 +100,6 @@ public class EnhancedPolarisGatewayReporterTest {
@Test
public void testRun() throws URISyntaxException {
APIConfig apiConfig = mock(APIConfig.class);
doReturn("0.0.0.0").when(apiConfig).getBindIP();
GlobalConfig globalConfig = mock(GlobalConfig.class);
doReturn(apiConfig).when(globalConfig).getAPI();
Configuration configuration = mock(Configuration.class);
doReturn(globalConfig).when(configuration).getGlobal();
doReturn(configuration).when(sdkContext).getConfig();
doReturn(new URI("http://0.0.0.0/")).when(request).getURI();
doReturn(new HttpHeaders()).when(request).getHeaders();
@ -124,9 +108,6 @@ public class EnhancedPolarisGatewayReporterTest {
doReturn(Mono.empty()).when(chain).filter(exchange);
ServiceInstance serviceInstance = mock(ServiceInstance.class);
doReturn("test").when(serviceInstance).getServiceId();
doReturn("0.0.0.0").when(serviceInstance).getHost();
doReturn(80).when(serviceInstance).getPort();
Response<ServiceInstance> serviceInstanceResponse = new Response<ServiceInstance>() {
@Override
public boolean hasServer() {
@ -142,14 +123,14 @@ public class EnhancedPolarisGatewayReporterTest {
doReturn(request).when(exchange).getRequest();
doReturn(response).when(exchange).getResponse();
EnhancedPolarisGatewayReporter reporter = new EnhancedPolarisGatewayReporter(reporterProperties, sdkContext, consumerAPI, circuitBreakAPI);
EnhancedGatewayGlobalFilter reporter = new EnhancedGatewayGlobalFilter(new DefaultEnhancedPluginRunner(new ArrayList<>()));
reporter.getOrder();
reporter.filter(exchange, chain).block();
doReturn(true).when(reporterProperties).isEnabled();
doReturn(Mono.error(new RuntimeException())).when(chain).filter(exchange);
reporter.filter(exchange, chain).block();
assertThatThrownBy(() -> reporter.filter(exchange, chain).block()).isInstanceOf(RuntimeException.class);
}
}

@ -19,17 +19,14 @@ package com.tencent.cloud.rpc.enhancement.webclient;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.polaris.api.config.Configuration;
import com.tencent.polaris.api.config.global.APIConfig;
import com.tencent.polaris.api.config.global.GlobalConfig;
import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner;
import com.tencent.polaris.client.api.SDKContext;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
@ -52,6 +49,7 @@ import org.springframework.web.reactive.function.client.ExchangeFunction;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
@ -66,10 +64,6 @@ public class EnhancedWebClientReporterTest {
@Mock
private SDKContext sdkContext;
@Mock
private ConsumerAPI consumerAPI;
@Mock
private CircuitBreakAPI circuitBreakAPI;
@Mock
private ClientRequest clientRequest;
@Mock
private ExchangeFunction exchangeFunction;
@ -101,16 +95,6 @@ public class EnhancedWebClientReporterTest {
}
@Test
public void testRun() throws URISyntaxException {
APIConfig apiConfig = mock(APIConfig.class);
doReturn("0.0.0.0").when(apiConfig).getBindIP();
GlobalConfig globalConfig = mock(GlobalConfig.class);
doReturn(apiConfig).when(globalConfig).getAPI();
Configuration configuration = mock(Configuration.class);
doReturn(globalConfig).when(configuration).getGlobal();
doReturn(configuration).when(sdkContext).getConfig();
doReturn(new URI("http://0.0.0.0/")).when(clientRequest).url();
doReturn(new HttpHeaders()).when(clientRequest).headers();
@ -119,14 +103,18 @@ public class EnhancedWebClientReporterTest {
doReturn(headers).when(clientResponse).headers();
doReturn(Mono.just(clientResponse)).when(exchangeFunction).exchange(any());
EnhancedWebClientReporter reporter = new EnhancedWebClientReporter(reporterProperties, sdkContext, consumerAPI, circuitBreakAPI);
EnhancedWebClientReporter reporter = new EnhancedWebClientReporter(new DefaultEnhancedPluginRunner(new ArrayList<>()));
ClientResponse clientResponse1 = reporter.filter(clientRequest, exchangeFunction).block();
assertThat(clientResponse1).isEqualTo(clientResponse);
doReturn(true).when(reporterProperties).isEnabled();
ClientResponse clientResponse2 = reporter.filter(clientRequest, exchangeFunction).block();
assertThat(clientResponse2).isEqualTo(clientResponse);
doReturn(Mono.error(new RuntimeException())).when(exchangeFunction).exchange(any());
assertThatThrownBy(() -> reporter.filter(clientRequest, exchangeFunction).block()).isInstanceOf(RuntimeException.class);
}
}

Loading…
Cancel
Save