feat:support traffic mirroring. (#1647)
parent
a01e79d279
commit
5f583ed146
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.quickstart.callee.pojo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User{" +
|
||||||
|
"name='" + name + '\'' +
|
||||||
|
", age=" + age +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.quickstart.callee.pojo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User{" +
|
||||||
|
"name='" + name + '\'' +
|
||||||
|
", age=" + age +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.quickstart.caller.pojo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User{" +
|
||||||
|
"name='" + name + '\'' +
|
||||||
|
", age=" + age +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.tsf.demo.consumer.entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User{" +
|
||||||
|
"name='" + name + '\'' +
|
||||||
|
", age=" + age +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>tsf-example</artifactId>
|
||||||
|
<groupId>com.tencent.cloud</groupId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>msgw-scg</artifactId>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.tencent.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-tencent-all</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.tsf.msgw.scg;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.tsf.annotation.EnableTsf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author seanlxliu
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableTsf
|
||||||
|
public class ScgApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(ScgApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
server:
|
||||||
|
port: 8080
|
||||||
|
error:
|
||||||
|
include-exception: true
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: msgw-scg
|
||||||
|
cloud:
|
||||||
|
gateway:
|
||||||
|
discovery:
|
||||||
|
locator:
|
||||||
|
enabled: true
|
||||||
|
lower-case-service-id: false
|
||||||
|
httpclient:
|
||||||
|
# The connect timeout in millis, the default is 45s.
|
||||||
|
connectTimeout: 200
|
||||||
|
responseTimeout: 10s
|
||||||
|
consul:
|
||||||
|
enabled: true
|
||||||
|
scheme: HTTP
|
||||||
|
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
root: INFO
|
||||||
|
file:
|
||||||
|
name: /tsf-demo-logs/${spring.application.name}/root.log
|
||||||
|
pattern:
|
||||||
|
level: "%-5level [${spring.application.name},%mdc{trace_id},%mdc{span_id},]"
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.tsf.demo.provider.entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User{" +
|
||||||
|
"name='" + name + '\'' +
|
||||||
|
", age=" + age +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>spring-cloud-tencent-plugin-starters</artifactId>
|
||||||
|
<groupId>com.tencent.cloud</groupId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>spring-cloud-starter-tencent-traffic-mirroring-plugin</artifactId>
|
||||||
|
<name>Spring Cloud Starter Tencent Traffic Mirroring Plugin</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- Spring Cloud Tencent dependencies start -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.tencent.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- Spring Cloud Tencent dependencies end -->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.plugin.trafficmirroring;
|
||||||
|
|
||||||
|
import com.tencent.cloud.plugin.trafficmirroring.config.TrafficMirroringProperties;
|
||||||
|
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traffic mirroring exception plugin.
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
public class TrafficMirroringExceptionPlugin extends TrafficMirroringPostPlugin {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(TrafficMirroringExceptionPlugin.class);
|
||||||
|
|
||||||
|
public TrafficMirroringExceptionPlugin(TrafficMirroringProperties trafficMirroringProperties) {
|
||||||
|
super(trafficMirroringProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return TrafficMirroringExceptionPlugin.class.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnhancedPluginType getType() {
|
||||||
|
return EnhancedPluginType.Client.EXCEPTION;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.plugin.trafficmirroring;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.tencent.cloud.common.metadata.MetadataContextHolder;
|
||||||
|
import com.tencent.cloud.plugin.trafficmirroring.config.TrafficMirroringProperties;
|
||||||
|
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.utils.EnhancedRequestUtils;
|
||||||
|
import com.tencent.polaris.api.plugin.route.RouterConstants;
|
||||||
|
import com.tencent.polaris.api.utils.ClassUtils;
|
||||||
|
import com.tencent.polaris.api.utils.StringUtils;
|
||||||
|
import com.tencent.polaris.client.pojo.Node;
|
||||||
|
import com.tencent.polaris.client.util.NamedThreadFactory;
|
||||||
|
import com.tencent.polaris.metadata.core.MetadataObjectValue;
|
||||||
|
import com.tencent.polaris.metadata.core.MetadataType;
|
||||||
|
import feign.Request;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpRequest;
|
||||||
|
|
||||||
|
import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.ClientPluginOrder.TRAFFIC_MIRRORING_PLUGIN_ORDER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traffic mirroring post plugin.
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
public class TrafficMirroringPostPlugin implements EnhancedPlugin {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(TrafficMirroringPostPlugin.class);
|
||||||
|
|
||||||
|
private final TrafficMirroringProperties trafficMirroringProperties;
|
||||||
|
|
||||||
|
private ThreadPoolExecutor threadPoolExecutor;
|
||||||
|
|
||||||
|
private HttpClient httpClient;
|
||||||
|
|
||||||
|
public TrafficMirroringPostPlugin(TrafficMirroringProperties trafficMirroringProperties) {
|
||||||
|
this.trafficMirroringProperties = trafficMirroringProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return TrafficMirroringPostPlugin.class.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnhancedPluginType getType() {
|
||||||
|
return EnhancedPluginType.Client.POST;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(EnhancedPluginContext context) throws Throwable {
|
||||||
|
if (!trafficMirroringProperties.isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object originalRequest = context.getOriginRequest();
|
||||||
|
// only RestTemplate and Feign request can be mirrored.
|
||||||
|
if (!(ClassUtils.isClassPresent("org.springframework.http.HttpRequest")
|
||||||
|
&& originalRequest instanceof HttpRequest)
|
||||||
|
&& !(ClassUtils.isClassPresent("feign.Request")
|
||||||
|
&& originalRequest instanceof Request)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get traffic mirroring address.
|
||||||
|
String destination = null;
|
||||||
|
try {
|
||||||
|
MetadataObjectValue<Node> metadataValue = MetadataContextHolder.get()
|
||||||
|
.getMetadataContainer(MetadataType.CUSTOM, false)
|
||||||
|
.getMetadataValue(RouterConstants.TRAFFIC_MIRRORING_NODE_KEY);
|
||||||
|
if (metadataValue != null) {
|
||||||
|
Optional<Node> trafficMirroringNode = metadataValue.getObjectValue();
|
||||||
|
if (trafficMirroringNode.isPresent()) {
|
||||||
|
destination = trafficMirroringNode.get().getHostPort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Throwable throwable) {
|
||||||
|
LOG.warn("Get traffic mirroring node failed.", throwable);
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(destination)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
initIfNeeded();
|
||||||
|
|
||||||
|
byte[] body = context.getOriginBody();
|
||||||
|
// send mirroring request.
|
||||||
|
try {
|
||||||
|
sendMirroringRequest(originalRequest, body, destination);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
LOG.warn("Traffic mirroring request failed.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initIfNeeded() {
|
||||||
|
if (threadPoolExecutor == null) {
|
||||||
|
// create thread pool executor.
|
||||||
|
int cpuCores = Runtime.getRuntime().availableProcessors();
|
||||||
|
int corePoolSize = cpuCores;
|
||||||
|
int maxPoolSize = trafficMirroringProperties.getRequestPoolSize();
|
||||||
|
if (cpuCores > trafficMirroringProperties.getRequestPoolSize()) {
|
||||||
|
corePoolSize = trafficMirroringProperties.getRequestPoolSize();
|
||||||
|
}
|
||||||
|
this.threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maxPoolSize,
|
||||||
|
60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory("polaris-traffic-mirroring"));
|
||||||
|
|
||||||
|
}
|
||||||
|
if (httpClient == null) {
|
||||||
|
// create JDK HttpClient instance.
|
||||||
|
this.httpClient = HttpClient.newBuilder()
|
||||||
|
.connectTimeout(Duration.ofMillis(trafficMirroringProperties.getRequestConnectionTimeout()))
|
||||||
|
.executor(threadPoolExecutor)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setHeaders(java.net.http.HttpRequest.Builder requestBuilder, Object originalRequest) {
|
||||||
|
if (ClassUtils.isClassPresent("org.springframework.http.HttpRequest")
|
||||||
|
&& originalRequest instanceof HttpRequest) {
|
||||||
|
HttpHeaders httpHeaders = ((HttpRequest) originalRequest).getHeaders();
|
||||||
|
httpHeaders.forEach((headerName, headerValues) -> {
|
||||||
|
if (shouldKeepHeader(headerName)) {
|
||||||
|
headerValues.forEach(headerValue ->
|
||||||
|
requestBuilder.header(headerName, headerValue));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (ClassUtils.isClassPresent("feign.Request")
|
||||||
|
&& originalRequest instanceof Request) {
|
||||||
|
Request request = (Request) originalRequest;
|
||||||
|
request.headers().forEach((headerName, headerValues) -> {
|
||||||
|
if (shouldKeepHeader(headerName)) {
|
||||||
|
headerValues.forEach(headerValue ->
|
||||||
|
requestBuilder.header(headerName, headerValue));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send mirroring request to specified destination.
|
||||||
|
*/
|
||||||
|
private void sendMirroringRequest(Object originalRequest, byte[] originalBody, String destination) {
|
||||||
|
// rebuilt mirroring url: replace original host with specified destination.
|
||||||
|
URI originalUri = EnhancedRequestUtils.getUri(originalRequest);
|
||||||
|
String method = EnhancedRequestUtils.getMethod(originalRequest);
|
||||||
|
String mirroringUrl = rebuildUrlWithDestination(originalUri, destination);
|
||||||
|
if (StringUtils.isBlank(mirroringUrl)) {
|
||||||
|
LOG.debug("Traffic mirroring request url is empty.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (originalBody == null) {
|
||||||
|
originalBody = new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// create JDK HttpRequest builder.
|
||||||
|
java.net.http.HttpRequest.Builder requestBuilder = java.net.http.HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create(mirroringUrl))
|
||||||
|
.method(method,
|
||||||
|
java.net.http.HttpRequest.BodyPublishers.ofByteArray(originalBody));
|
||||||
|
|
||||||
|
// copy request headers (except some special headers).
|
||||||
|
setHeaders(requestBuilder, originalRequest);
|
||||||
|
|
||||||
|
// build request.
|
||||||
|
java.net.http.HttpRequest mirrorRequest = requestBuilder.build();
|
||||||
|
|
||||||
|
// send async request (ignore response).
|
||||||
|
httpClient.sendAsync(mirrorRequest, HttpResponse.BodyHandlers.discarding())
|
||||||
|
.thenAccept(response -> {
|
||||||
|
if (response.statusCode() >= 400) {
|
||||||
|
LOG.warn("Traffic mirroring async request return: {}", response.statusCode());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG.debug("Traffic mirroring async request return: {}", response.statusCode());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.exceptionally(ex -> {
|
||||||
|
LOG.warn("Traffic mirroring async request failed", ex);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebuild url with specified destination.
|
||||||
|
*/
|
||||||
|
private String rebuildUrlWithDestination(URI originalUri, String destination) {
|
||||||
|
if (StringUtils.isBlank(destination)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String scheme = originalUri.getScheme();
|
||||||
|
String path = originalUri.getRawPath();
|
||||||
|
String query = originalUri.getRawQuery();
|
||||||
|
|
||||||
|
// fill default port.
|
||||||
|
if (!StringUtils.contains(destination, ":")) {
|
||||||
|
destination += (scheme.equals("https") ? ":443" : ":80");
|
||||||
|
}
|
||||||
|
|
||||||
|
// build full mirroring url.
|
||||||
|
String finalUrl = String.format("%s://%s%s%s",
|
||||||
|
scheme,
|
||||||
|
destination,
|
||||||
|
path != null ? path : "",
|
||||||
|
query != null ? "?" + query : "");
|
||||||
|
LOG.debug("Traffic mirroring request url: {}", finalUrl);
|
||||||
|
|
||||||
|
return finalUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check header should be kept.
|
||||||
|
*/
|
||||||
|
private boolean shouldKeepHeader(String headerName) {
|
||||||
|
return !headerName.equalsIgnoreCase("connection") &&
|
||||||
|
!headerName.equalsIgnoreCase("content-length") &&
|
||||||
|
!headerName.equalsIgnoreCase("expect") &&
|
||||||
|
!headerName.equalsIgnoreCase("host") &&
|
||||||
|
!headerName.equalsIgnoreCase("upgrade");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handlerThrowable(EnhancedPluginContext context, Throwable throwable) {
|
||||||
|
LOG.error("TrafficMirroringPostPlugin runs failed. context=[{}].", context, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return TRAFFIC_MIRRORING_PLUGIN_ORDER;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.plugin.trafficmirroring.config;
|
||||||
|
|
||||||
|
import com.tencent.cloud.plugin.trafficmirroring.TrafficMirroringExceptionPlugin;
|
||||||
|
import com.tencent.cloud.plugin.trafficmirroring.TrafficMirroringPostPlugin;
|
||||||
|
import com.tencent.cloud.polaris.router.config.ConditionalOnPolarisRouterEnabled;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto configuration for traffic mirroring plugin.
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ConditionalOnPolarisRouterEnabled
|
||||||
|
@ConditionalOnProperty(value = "spring.cloud.polaris.traffic-mirroring.enabled", matchIfMissing = true)
|
||||||
|
@EnableConfigurationProperties(TrafficMirroringProperties.class)
|
||||||
|
public class TrafficMirroringAutoConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TrafficMirroringPostPlugin trafficMirrorPostPlugin(TrafficMirroringProperties trafficMirrorProperties) {
|
||||||
|
return new TrafficMirroringPostPlugin(trafficMirrorProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TrafficMirroringExceptionPlugin trafficMirrorExceptionPlugin(TrafficMirroringProperties trafficMirrorProperties) {
|
||||||
|
return new TrafficMirroringExceptionPlugin(trafficMirrorProperties);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.plugin.trafficmirroring.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties for traffic mirroring.
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties("spring.cloud.polaris.traffic-mirroring")
|
||||||
|
public class TrafficMirroringProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If traffic mirroring is enabled. Default is true.
|
||||||
|
*/
|
||||||
|
private boolean enabled = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traffic mirroring request pool size. Default is 100.
|
||||||
|
*/
|
||||||
|
private int requestPoolSize = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traffic mirroring request connection timeout in millisecond. Default is 5000.
|
||||||
|
*/
|
||||||
|
private long requestConnectionTimeout = 5000;
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRequestPoolSize() {
|
||||||
|
return requestPoolSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestPoolSize(int requestPoolSize) {
|
||||||
|
this.requestPoolSize = requestPoolSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRequestConnectionTimeout() {
|
||||||
|
return requestConnectionTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestConnectionTimeout(long requestConnectionTimeout) {
|
||||||
|
this.requestConnectionTimeout = requestConnectionTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TrafficMirroringProperties{" +
|
||||||
|
"enabled=" + enabled +
|
||||||
|
", requestPoolSize=" + requestPoolSize +
|
||||||
|
", requestConnectionTimeout=" + requestConnectionTimeout +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
com.tencent.cloud.plugin.trafficmirroring.config.TrafficMirroringAutoConfiguration
|
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.plugin.trafficmirroring.config;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link TrafficMirroringProperties}.
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
public class TrafficMirroringPropertiesTest {
|
||||||
|
@Test
|
||||||
|
void testDefaultValues() {
|
||||||
|
TrafficMirroringProperties properties = new TrafficMirroringProperties();
|
||||||
|
|
||||||
|
assertThat(properties.isEnabled()).isTrue();
|
||||||
|
assertThat(properties.getRequestPoolSize()).isEqualTo(4);
|
||||||
|
assertThat(properties.getRequestConnectionTimeout()).isEqualTo(5000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEnabledProperty() {
|
||||||
|
TrafficMirroringProperties properties = new TrafficMirroringProperties();
|
||||||
|
|
||||||
|
properties.setEnabled(false);
|
||||||
|
|
||||||
|
assertThat(properties.isEnabled()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRequestPoolSizeProperty() {
|
||||||
|
TrafficMirroringProperties properties = new TrafficMirroringProperties();
|
||||||
|
|
||||||
|
properties.setRequestPoolSize(10);
|
||||||
|
|
||||||
|
assertThat(properties.getRequestPoolSize()).isEqualTo(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRequestPoolSizeBoundaryValues() {
|
||||||
|
TrafficMirroringProperties properties = new TrafficMirroringProperties();
|
||||||
|
|
||||||
|
properties.setRequestPoolSize(0);
|
||||||
|
assertThat(properties.getRequestPoolSize()).isZero();
|
||||||
|
|
||||||
|
properties.setRequestPoolSize(-5);
|
||||||
|
assertThat(properties.getRequestPoolSize()).isNegative();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRequestConnectionTimeoutProperty() {
|
||||||
|
TrafficMirroringProperties properties = new TrafficMirroringProperties();
|
||||||
|
|
||||||
|
properties.setRequestConnectionTimeout(3000L);
|
||||||
|
|
||||||
|
assertThat(properties.getRequestConnectionTimeout()).isEqualTo(3000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRequestConnectionTimeoutBoundaryValues() {
|
||||||
|
TrafficMirroringProperties properties = new TrafficMirroringProperties();
|
||||||
|
|
||||||
|
properties.setRequestConnectionTimeout(0L);
|
||||||
|
assertThat(properties.getRequestConnectionTimeout()).isZero();
|
||||||
|
|
||||||
|
properties.setRequestConnectionTimeout(-1000L);
|
||||||
|
assertThat(properties.getRequestConnectionTimeout()).isNegative();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToString() {
|
||||||
|
TrafficMirroringProperties properties = new TrafficMirroringProperties();
|
||||||
|
properties.setEnabled(false);
|
||||||
|
properties.setRequestPoolSize(8);
|
||||||
|
properties.setRequestConnectionTimeout(2000L);
|
||||||
|
|
||||||
|
String result = properties.toString();
|
||||||
|
|
||||||
|
assertThat(result)
|
||||||
|
.contains("enabled=false")
|
||||||
|
.contains("requestPoolSize=8")
|
||||||
|
.contains("requestConnectionTimeout=2000");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Tencent. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the BSD 3-Clause License (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.tencent.cloud.rpc.enhancement.utils;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import com.tencent.polaris.api.utils.ClassUtils;
|
||||||
|
import feign.Request;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utils for enhanced request.
|
||||||
|
*
|
||||||
|
* @author Haotian Zhang
|
||||||
|
*/
|
||||||
|
public final class EnhancedRequestUtils {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(EnhancedRequestUtils.class);
|
||||||
|
|
||||||
|
private EnhancedRequestUtils() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get uri from original request.
|
||||||
|
*
|
||||||
|
* @param originalRequest original request
|
||||||
|
* @return URI
|
||||||
|
*/
|
||||||
|
public static URI getUri(Object originalRequest) {
|
||||||
|
URI uri = null;
|
||||||
|
if (ClassUtils.isClassPresent("org.springframework.http.HttpRequest")
|
||||||
|
&& originalRequest instanceof HttpRequest) {
|
||||||
|
HttpRequest httpRequest = (HttpRequest) originalRequest;
|
||||||
|
uri = httpRequest.getURI();
|
||||||
|
LOG.debug("Get uri: {} from org.springframework.http.HttpRequest", uri);
|
||||||
|
}
|
||||||
|
else if (ClassUtils.isClassPresent("feign.Request")
|
||||||
|
&& originalRequest instanceof Request) {
|
||||||
|
Request request = (Request) originalRequest;
|
||||||
|
uri = URI.create(request.url());
|
||||||
|
LOG.debug("Get uri: {} from feign.Request", uri);
|
||||||
|
}
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get method from original request.
|
||||||
|
*
|
||||||
|
* @param originalRequest original request
|
||||||
|
* @return method
|
||||||
|
*/
|
||||||
|
public static String getMethod(Object originalRequest) {
|
||||||
|
String method = "GET";
|
||||||
|
if (ClassUtils.isClassPresent("org.springframework.http.HttpRequest")
|
||||||
|
&& originalRequest instanceof HttpRequest) {
|
||||||
|
method = ((HttpRequest) originalRequest).getMethod().name();
|
||||||
|
LOG.debug("Get method: {} from org.springframework.http.HttpRequest", method);
|
||||||
|
}
|
||||||
|
else if (ClassUtils.isClassPresent("feign.Request")
|
||||||
|
&& originalRequest instanceof Request) {
|
||||||
|
method = ((Request) originalRequest).httpMethod().name();
|
||||||
|
LOG.debug("Get method: {} from feign.Request", method);
|
||||||
|
}
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue