pull/963/head
seanyu 2 years ago
parent 13ab4b610d
commit 1c587b7f83

@ -22,6 +22,8 @@ import java.util.List;
import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory; import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory;
import com.tencent.cloud.polaris.circuitbreaker.common.CircuitBreakerConfigModifier; 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.polaris.circuitbreaker.resttemplate.PolarisCircuitBreakerRestTemplateBeanPostProcessor;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
@ -61,6 +63,20 @@ public class PolarisCircuitBreakerAutoConfiguration {
return CircuitBreakAPIFactory.createCircuitBreakAPIByContext(polarisContext); 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 @Bean
@ConditionalOnMissingBean(CircuitBreakerFactory.class) @ConditionalOnMissingBean(CircuitBreakerFactory.class)
public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { 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.ReactivePolarisCircuitBreakerFactory;
import com.tencent.cloud.polaris.circuitbreaker.common.CircuitBreakerConfigModifier; 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.RpcEnhancementAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.core.ConsumerAPI;
@ -59,6 +61,20 @@ public class ReactivePolarisCircuitBreakerAutoConfiguration {
return CircuitBreakAPIFactory.createCircuitBreakAPIByContext(polarisContext); 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 @Bean
@ConditionalOnMissingBean(ReactiveCircuitBreakerFactory.class) @ConditionalOnMissingBean(ReactiveCircuitBreakerFactory.class)
public ReactiveCircuitBreakerFactory polarisReactiveCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { 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 enabled: true
rejectRequestTipsFilePath: reject-tips.html rejectRequestTipsFilePath: reject-tips.html
maxQueuingTime: 500 maxQueuingTime: 500
stat:
enabled: true
port: 28083
management: management:
endpoints: endpoints:
web: web:

@ -32,41 +32,6 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </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 --> <!-- Polaris dependencies end -->
<dependency> <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 * @author <a href="mailto:iskp.me@gmail.com">Elve.Xu</a> 2022-07-11
*/ */
public abstract class AbstractPolarisReporterAdapter { public abstract class AbstractPolarisReporterAdapter {
private static final Logger LOG = LoggerFactory.getLogger(AbstractPolarisReporterAdapter.class); private static final Logger LOG = LoggerFactory.getLogger(AbstractPolarisReporterAdapter.class);
private static final List<HttpStatus> HTTP_STATUSES = toList(NOT_IMPLEMENTED, BAD_GATEWAY, private static final List<HttpStatus> HTTP_STATUSES = toList(NOT_IMPLEMENTED, BAD_GATEWAY,
SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT, HTTP_VERSION_NOT_SUPPORTED, VARIANT_ALSO_NEGOTIATES, SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT, HTTP_VERSION_NOT_SUPPORTED, VARIANT_ALSO_NEGOTIATES,
@ -88,13 +87,6 @@ public abstract class AbstractPolarisReporterAdapter {
this.context = context; 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. * createServiceCallResult.
* @param calleeServiceName will pick up url host when null * @param calleeServiceName will pick up url host when null
@ -129,13 +121,6 @@ public abstract class AbstractPolarisReporterAdapter {
return resultRequest; 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. * createInstanceResourceStat.
* @param calleeServiceName will pick up url host when null * @param calleeServiceName will pick up url host when null
@ -261,16 +246,18 @@ public abstract class AbstractPolarisReporterAdapter {
} }
private String getLabels(HttpHeaders headers) { private String getLabels(HttpHeaders headers) {
Collection<String> labels = headers.get(RouterConstant.ROUTER_LABEL_HEADER); if (headers != null) {
if (CollectionUtils.isNotEmpty(labels) && labels.iterator().hasNext()) { Collection<String> labels = headers.get(RouterConstant.ROUTER_LABEL_HEADER);
String label = labels.iterator().next(); if (CollectionUtils.isNotEmpty(labels) && labels.iterator().hasNext()) {
try { String label = labels.iterator().next();
label = URLDecoder.decode(label, UTF_8); try {
} label = URLDecoder.decode(label, UTF_8);
catch (UnsupportedEncodingException e) { }
LOG.error("unsupported charset exception " + UTF_8, e); catch (UnsupportedEncodingException e) {
LOG.error("unsupported charset exception " + UTF_8, e);
}
return RequestLabelUtils.convertLabel(label);
} }
return RequestLabelUtils.convertLabel(label);
} }
return null; return null;
} }

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

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

@ -18,17 +18,26 @@
package com.tencent.cloud.rpc.enhancement.feign; package com.tencent.cloud.rpc.enhancement.feign;
import java.io.IOException; 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.Client;
import feign.Request; import feign.Request;
import feign.Request.Options; import feign.Request.Options;
import feign.Response; import feign.Response;
import static com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType.EXCEPTION; import org.springframework.cloud.client.DefaultServiceInstance;
import static com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType.FINALLY; import org.springframework.http.HttpHeaders;
import static com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType.POST; import org.springframework.http.HttpMethod;
import static com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType.PRE;
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; import static feign.Util.checkNotNull;
/** /**
@ -40,40 +49,64 @@ public class EnhancedFeignClient implements Client {
private final Client delegate; 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.delegate = checkNotNull(target, "target");
this.pluginRunner = pluginRunner; this.pluginRunner = pluginRunner;
} }
@Override @Override
public Response execute(Request request, Options options) throws IOException { public Response execute(Request request, Options options) throws IOException {
EnhancedFeignContext enhancedFeignContext = new EnhancedFeignContext(); EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
enhancedFeignContext.setRequest(request);
enhancedFeignContext.setOptions(options); 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. // Run pre enhanced plugins.
pluginRunner.run(PRE, enhancedFeignContext); pluginRunner.run(PRE, enhancedPluginContext);
long startMillis = System.currentTimeMillis();
try { try {
long startMillis = System.currentTimeMillis();
Response response = delegate.execute(request, options); Response response = delegate.execute(request, options);
enhancedFeignContext.setDelay(System.currentTimeMillis() - startMillis); enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
enhancedFeignContext.setResponse(response);
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. // Run post enhanced plugins.
pluginRunner.run(POST, enhancedFeignContext); pluginRunner.run(POST, enhancedPluginContext);
return response; return response;
} }
catch (IOException origin) { catch (IOException origin) {
enhancedFeignContext.setException(origin); enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
enhancedPluginContext.setThrowable(origin);
// Run exception enhanced feign plugins. // Run exception enhanced feign plugins.
pluginRunner.run(EXCEPTION, enhancedFeignContext); pluginRunner.run(EXCEPTION, enhancedPluginContext);
throw origin; throw origin;
} }
finally { finally {
// Run finally enhanced feign plugins. // Run finally enhanced plugins.
pluginRunner.run(FINALLY, enhancedFeignContext); 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.Comparator;
import java.util.List; import java.util.List;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap; 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; import org.springframework.util.CollectionUtils;
@ -34,14 +31,14 @@ import org.springframework.util.CollectionUtils;
* *
* @author Derek Yi 2022-08-16 * @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) { public DefaultEnhancedPluginRunner(List<EnhancedPlugin> enhancedPlugins) {
if (!CollectionUtils.isEmpty(enhancedFeignPlugins)) { if (!CollectionUtils.isEmpty(enhancedPlugins)) {
enhancedFeignPlugins.stream() enhancedPlugins.stream()
.sorted(Comparator.comparing(EnhancedFeignPlugin::getOrder)) .sorted(Comparator.comparing(EnhancedPlugin::getOrder))
.forEach(plugin -> pluginMap.put(plugin.getType().name(), plugin)); .forEach(plugin -> pluginMap.put(plugin.getType().name(), plugin));
} }
} }
@ -53,8 +50,8 @@ public class DefaultEnhancedFeignPluginRunner implements EnhancedFeignPluginRunn
* @param context context in enhanced feign client. * @param context context in enhanced feign client.
*/ */
@Override @Override
public void run(EnhancedFeignPluginType pluginType, EnhancedFeignContext context) { public void run(EnhancedPluginType pluginType, EnhancedPluginContext context) {
for (EnhancedFeignPlugin plugin : pluginMap.get(pluginType.name())) { for (EnhancedPlugin plugin : pluginMap.get(pluginType.name())) {
try { try {
plugin.run(context); plugin.run(context);
} }

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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; import org.springframework.core.Ordered;
@ -24,7 +24,7 @@ import org.springframework.core.Ordered;
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
public interface EnhancedFeignPlugin extends Ordered { public interface EnhancedPlugin extends Ordered {
/** /**
* Get name of plugin. * Get name of plugin.
@ -38,9 +38,9 @@ public interface EnhancedFeignPlugin extends Ordered {
/** /**
* Get type of plugin. * Get type of plugin.
* *
* @return {@link EnhancedFeignPluginType} * @return {@link EnhancedPluginType}
*/ */
EnhancedFeignPluginType getType(); EnhancedPluginType getType();
/** /**
* Run the plugin. * Run the plugin.
@ -48,15 +48,15 @@ public interface EnhancedFeignPlugin extends Ordered {
* @param context context in enhanced feign client. * @param context context in enhanced feign client.
* @throws Throwable throwable thrown from run method. * @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 context context in enhanced feign client.
* @param throwable throwable thrown from run method. * @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; package com.tencent.cloud.rpc.enhancement.plugin;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType;
/** /**
* Plugin runner. * Plugin runner.
* *
* @author Derek Yi 2022-08-16 * @author Derek Yi 2022-08-16
*/ */
public interface EnhancedFeignPluginRunner { public interface EnhancedPluginRunner {
/** /**
* run the plugin. * run the plugin.
@ -34,5 +31,5 @@ public interface EnhancedFeignPluginRunner {
* @param pluginType type of plugin * @param pluginType type of plugin
* @param context context in enhanced feign client. * @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. * 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 * @author Haotian Zhang
*/ */
public enum EnhancedFeignPluginType { public enum EnhancedPluginType {
/** /**
* Pre feign plugin. * 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.constant.HeaderConstant;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
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 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.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction; import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.ExchangeFunction; 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. * EnhancedWebClientReporter.
* *
* @author sean yu * @author sean yu
*/ */
public class EnhancedWebClientReporter extends AbstractPolarisReporterAdapter implements ExchangeFilterFunction { public class EnhancedWebClientReporter implements ExchangeFilterFunction {
private static final Logger LOG = LoggerFactory.getLogger(EnhancedWebClientReporter.class); private final EnhancedPluginRunner pluginRunner;
private final ConsumerAPI consumerAPI;
public EnhancedWebClientReporter(EnhancedPluginRunner pluginRunner) {
private final CircuitBreakAPI circuitBreakAPI; this.pluginRunner = pluginRunner;
public EnhancedWebClientReporter(RpcEnhancementReporterProperties reportProperties,
SDKContext context,
ConsumerAPI consumerAPI,
CircuitBreakAPI circuitBreakAPI) {
super(reportProperties, context);
this.consumerAPI = consumerAPI;
this.circuitBreakAPI = circuitBreakAPI;
} }
@Override @Override
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) { public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
if (!reportProperties.isEnabled()) { EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
return next.exchange(request);
} EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpHeaders(request.headers())
.httpMethod(request.method())
.url(request.url())
.build();
enhancedPluginContext.setRequest(enhancedRequestContext);
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
return next.exchange(request) return next.exchange(request)
.doOnSuccess(response -> instrumentResponse(request, response, null, startTime)) .doOnSuccess(response -> {
.doOnError(t -> instrumentResponse(request, null, t, startTime)); 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) { // Run exception enhanced plugins.
Map<String, String> loadBalancerContext = MetadataContextHolder.get().getLoadbalancerMetadata(); pluginRunner.run(EXCEPTION, enhancedPluginContext);
String serviceId = loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_SERVICE_ID); })
long delay = System.currentTimeMillis() - startTime; .doFinally(v -> {
// Run finally enhanced plugins.
HttpHeaders requestHeaders = request.headers(); pluginRunner.run(FINALLY, enhancedPluginContext);
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);
} }
} }

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

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

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

@ -22,9 +22,10 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext; import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import feign.Client; import feign.Client;
import feign.Request; import feign.Request;
import feign.RequestTemplate; import feign.RequestTemplate;
@ -72,9 +73,9 @@ public class EnhancedFeignClientTest {
fail("Exception encountered.", e); fail("Exception encountered.", e);
} }
List<EnhancedFeignPlugin> enhancedFeignPlugins = getMockEnhancedFeignPlugins(); List<EnhancedPlugin> enhancedPlugins = getMockEnhancedFeignPlugins();
try { try {
new EnhancedFeignClient(mock(Client.class), new DefaultEnhancedFeignPluginRunner(enhancedFeignPlugins)); new EnhancedFeignClient(mock(Client.class), new DefaultEnhancedPluginRunner(enhancedPlugins));
} }
catch (Throwable e) { catch (Throwable e) {
fail("Exception encountered.", e); fail("Exception encountered.", e);
@ -103,7 +104,7 @@ public class EnhancedFeignClientTest {
RequestTemplate requestTemplate = new RequestTemplate(); RequestTemplate requestTemplate = new RequestTemplate();
requestTemplate.feignTarget(target); requestTemplate.feignTarget(target);
EnhancedFeignClient polarisFeignClient = new EnhancedFeignClient(delegate, new DefaultEnhancedFeignPluginRunner(getMockEnhancedFeignPlugins())); EnhancedFeignClient polarisFeignClient = new EnhancedFeignClient(delegate, new DefaultEnhancedPluginRunner(getMockEnhancedFeignPlugins()));
// 200 // 200
Response response = polarisFeignClient.execute(Request.create(Request.HttpMethod.GET, "http://localhost:8080/test", Response response = polarisFeignClient.execute(Request.create(Request.HttpMethod.GET, "http://localhost:8080/test",
@ -127,22 +128,22 @@ public class EnhancedFeignClientTest {
} }
} }
private List<EnhancedFeignPlugin> getMockEnhancedFeignPlugins() { private List<EnhancedPlugin> getMockEnhancedFeignPlugins() {
List<EnhancedFeignPlugin> enhancedFeignPlugins = new ArrayList<>(); List<EnhancedPlugin> enhancedPlugins = new ArrayList<>();
enhancedFeignPlugins.add(new EnhancedFeignPlugin() { enhancedPlugins.add(new EnhancedPlugin() {
@Override @Override
public EnhancedFeignPluginType getType() { public EnhancedPluginType getType() {
return EnhancedFeignPluginType.PRE; return EnhancedPluginType.PRE;
} }
@Override @Override
public void run(EnhancedFeignContext context) { public void run(EnhancedPluginContext context) {
} }
@Override @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 @Override
public EnhancedFeignPluginType getType() { public EnhancedPluginType getType() {
return EnhancedFeignPluginType.POST; return EnhancedPluginType.POST;
} }
@Override @Override
public void run(EnhancedFeignContext context) { public void run(EnhancedPluginContext context) {
} }
@Override @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 @Override
public EnhancedFeignPluginType getType() { public EnhancedPluginType getType() {
return EnhancedFeignPluginType.EXCEPTION; return EnhancedPluginType.EXCEPTION;
} }
@Override @Override
public void run(EnhancedFeignContext context) { public void run(EnhancedPluginContext context) {
} }
@Override @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 @Override
public EnhancedFeignPluginType getType() { public EnhancedPluginType getType() {
return EnhancedFeignPluginType.FINALLY; return EnhancedPluginType.FINALLY;
} }
@Override @Override
public void run(EnhancedFeignContext context) { public void run(EnhancedPluginContext context) {
} }
@Override @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. * 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.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext; import com.tencent.cloud.rpc.enhancement.plugin.reporter.ExceptionPolarisReporter;
import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType;
import com.tencent.polaris.api.config.Configuration; import com.tencent.polaris.api.config.Configuration;
import com.tencent.polaris.api.config.global.APIConfig; import com.tencent.polaris.api.config.global.APIConfig;
import com.tencent.polaris.api.config.global.GlobalConfig; import com.tencent.polaris.api.config.global.GlobalConfig;
import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext; 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.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -45,6 +39,10 @@ import org.mockito.MockedStatic;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; 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.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; 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.assertThat;
@ -67,12 +65,10 @@ public class ExceptionPolarisReporterTest {
private RpcEnhancementReporterProperties reporterProperties; private RpcEnhancementReporterProperties reporterProperties;
@Mock @Mock
private SDKContext sdkContext; private SDKContext sdkContext;
@Mock
private ConsumerAPI consumerAPI;
@Mock
private CircuitBreakAPI circuitBreakAPI;
@InjectMocks @InjectMocks
private ExceptionPolarisReporter exceptionPolarisReporter; private ExceptionPolarisReporter exceptionPolarisReporter;
@Mock
private ConsumerAPI consumerAPI;
@BeforeAll @BeforeAll
static void beforeAll() { static void beforeAll() {
@ -99,20 +95,17 @@ public class ExceptionPolarisReporterTest {
@Test @Test
public void testType() { public void testType() {
assertThat(exceptionPolarisReporter.getType()).isEqualTo(EnhancedFeignPluginType.EXCEPTION); assertThat(exceptionPolarisReporter.getType()).isEqualTo(EnhancedPluginType.EXCEPTION);
} }
@Test @Test
public void testRun() { public void testRun() {
EnhancedFeignContext context = mock(EnhancedFeignContext.class); EnhancedPluginContext context = mock(EnhancedPluginContext.class);
// test not report // test not report
exceptionPolarisReporter.run(context); exceptionPolarisReporter.run(context);
verify(context, times(0)).getRequest(); verify(context, times(0)).getRequest();
doReturn(true).when(reporterProperties).isEnabled(); doReturn(true).when(reporterProperties).isEnabled();
// mock target
Target<?> target = mock(Target.class);
doReturn(SERVICE_PROVIDER).when(target).name();
APIConfig apiConfig = mock(APIConfig.class); APIConfig apiConfig = mock(APIConfig.class);
doReturn("0.0.0.0").when(apiConfig).getBindIP(); doReturn("0.0.0.0").when(apiConfig).getBindIP();
@ -125,29 +118,37 @@ public class ExceptionPolarisReporterTest {
doReturn(configuration).when(sdkContext).getConfig(); doReturn(configuration).when(sdkContext).getConfig();
// mock RequestTemplate.class EnhancedPluginContext pluginContext = new EnhancedPluginContext();
RequestTemplate requestTemplate = new RequestTemplate(); EnhancedRequestContext request = EnhancedRequestContext.builder()
requestTemplate.feignTarget(target); .httpMethod(HttpMethod.GET)
.url(URI.create("http://0.0.0.0/"))
EnhancedFeignContext feignContext = new EnhancedFeignContext(); .httpHeaders(new HttpHeaders())
Request request = Request.create(Request.HttpMethod.GET, "http://0.0.0.0/", new HashMap<>(), null, null, requestTemplate); .build();
Response response = Response.builder() EnhancedResponseContext response = EnhancedResponseContext.builder()
.request(request) .httpStatus(200)
.build(); .build();
feignContext.setRequest(request); DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
feignContext.setResponse(response); serviceInstance.setServiceId(SERVICE_PROVIDER);
exceptionPolarisReporter.run(feignContext);
pluginContext.setRequest(request);
pluginContext.setResponse(response);
pluginContext.setServiceInstance(serviceInstance);
pluginContext.setThrowable(new RuntimeException());
exceptionPolarisReporter.run(pluginContext);
exceptionPolarisReporter.getOrder(); exceptionPolarisReporter.getOrder();
exceptionPolarisReporter.getName();
exceptionPolarisReporter.getType();
} }
@Test @Test
public void testHandlerThrowable() { public void testHandlerThrowable() {
// mock request // mock request
Request request = mock(Request.class); EnhancedRequestContext request = mock(EnhancedRequestContext.class);
// mock response // mock response
Response response = mock(Response.class); EnhancedResponseContext response = mock(EnhancedResponseContext.class);
EnhancedFeignContext context = new EnhancedFeignContext(); EnhancedPluginContext context = new EnhancedPluginContext();
context.setRequest(request); context.setRequest(request);
context.setResponse(response); context.setResponse(response);
exceptionPolarisReporter.handlerThrowable(context, new RuntimeException("Mock exception.")); exceptionPolarisReporter.handlerThrowable(context, new RuntimeException("Mock exception."));

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

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

@ -19,17 +19,14 @@ package com.tencent.cloud.rpc.enhancement.scg;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.ArrayList;
import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.polaris.api.config.Configuration; import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner;
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 com.tencent.polaris.client.api.SDKContext;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; 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.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; 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.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_LOADBALANCER_RESPONSE_ATTR; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_LOADBALANCER_RESPONSE_ATTR;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
public class EnhancedPolarisGatewayReporterTest { public class EnhancedGatewayGlobalFilterTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils; private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@Mock @Mock
@ -68,10 +66,6 @@ public class EnhancedPolarisGatewayReporterTest {
@Mock @Mock
private SDKContext sdkContext; private SDKContext sdkContext;
@Mock @Mock
private ConsumerAPI consumerAPI;
@Mock
private CircuitBreakAPI circuitBreakAPI;
@Mock
ServerWebExchange exchange; ServerWebExchange exchange;
@Mock @Mock
GatewayFilterChain chain; GatewayFilterChain chain;
@ -106,16 +100,6 @@ public class EnhancedPolarisGatewayReporterTest {
@Test @Test
public void testRun() throws URISyntaxException { 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 URI("http://0.0.0.0/")).when(request).getURI();
doReturn(new HttpHeaders()).when(request).getHeaders(); doReturn(new HttpHeaders()).when(request).getHeaders();
@ -124,9 +108,6 @@ public class EnhancedPolarisGatewayReporterTest {
doReturn(Mono.empty()).when(chain).filter(exchange); doReturn(Mono.empty()).when(chain).filter(exchange);
ServiceInstance serviceInstance = mock(ServiceInstance.class); 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>() { Response<ServiceInstance> serviceInstanceResponse = new Response<ServiceInstance>() {
@Override @Override
public boolean hasServer() { public boolean hasServer() {
@ -142,14 +123,14 @@ public class EnhancedPolarisGatewayReporterTest {
doReturn(request).when(exchange).getRequest(); doReturn(request).when(exchange).getRequest();
doReturn(response).when(exchange).getResponse(); doReturn(response).when(exchange).getResponse();
EnhancedPolarisGatewayReporter reporter = new EnhancedPolarisGatewayReporter(reporterProperties, sdkContext, consumerAPI, circuitBreakAPI); EnhancedGatewayGlobalFilter reporter = new EnhancedGatewayGlobalFilter(new DefaultEnhancedPluginRunner(new ArrayList<>()));
reporter.getOrder(); reporter.getOrder();
reporter.filter(exchange, chain).block(); 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.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.ArrayList;
import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.polaris.api.config.Configuration; import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner;
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 com.tencent.polaris.client.api.SDKContext;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; 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.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; 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.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
@ -66,10 +64,6 @@ public class EnhancedWebClientReporterTest {
@Mock @Mock
private SDKContext sdkContext; private SDKContext sdkContext;
@Mock @Mock
private ConsumerAPI consumerAPI;
@Mock
private CircuitBreakAPI circuitBreakAPI;
@Mock
private ClientRequest clientRequest; private ClientRequest clientRequest;
@Mock @Mock
private ExchangeFunction exchangeFunction; private ExchangeFunction exchangeFunction;
@ -101,16 +95,6 @@ public class EnhancedWebClientReporterTest {
} }
@Test @Test
public void testRun() throws URISyntaxException { 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 URI("http://0.0.0.0/")).when(clientRequest).url();
doReturn(new HttpHeaders()).when(clientRequest).headers(); doReturn(new HttpHeaders()).when(clientRequest).headers();
@ -119,14 +103,18 @@ public class EnhancedWebClientReporterTest {
doReturn(headers).when(clientResponse).headers(); doReturn(headers).when(clientResponse).headers();
doReturn(Mono.just(clientResponse)).when(exchangeFunction).exchange(any()); 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(); ClientResponse clientResponse1 = reporter.filter(clientRequest, exchangeFunction).block();
assertThat(clientResponse1).isEqualTo(clientResponse); assertThat(clientResponse1).isEqualTo(clientResponse);
doReturn(true).when(reporterProperties).isEnabled();
ClientResponse clientResponse2 = reporter.filter(clientRequest, exchangeFunction).block(); ClientResponse clientResponse2 = reporter.filter(clientRequest, exchangeFunction).block();
assertThat(clientResponse2).isEqualTo(clientResponse); 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