Support for tracing webflux-6.x and gateway-4.x (#661)
This commit is contained in:
parent
c5d62cb97a
commit
7aec68263b
|
|
@ -57,6 +57,7 @@ jobs:
|
|||
case:
|
||||
- spring-6.x-scenario
|
||||
- resteasy-6.x-scenario
|
||||
- gateway-4.x-scenario
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ Release Notes.
|
|||
|
||||
* Fix NoSuchMethodError in mvc-annotation-commons and change deprecated method.
|
||||
* fix forkjoinpool plugin in JDK11。
|
||||
* Support for tracing spring-cloud-gateway 4.x in gateway-4.x-plugin.
|
||||
|
||||
|
||||
#### Documentation
|
||||
|
||||
|
|
|
|||
|
|
@ -20,13 +20,16 @@ package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v3x.define;
|
|||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
|
||||
/**
|
||||
* This abstract class defines the <code>witnessClasses()</code> method,
|
||||
* and other plugin define classes need to inherit from this class
|
||||
* This abstract class defines the <code>witnessClasses()</code> method, and other plugin define classes need to inherit
|
||||
* from this class
|
||||
*/
|
||||
public abstract class AbstractGatewayV3EnhancePluginDefine extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
@Override
|
||||
protected String[] witnessClasses() {
|
||||
return new String[]{"org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties"};
|
||||
return new String[] {
|
||||
"org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties",
|
||||
"org.springframework.web.client.AsyncRestTemplate"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>optional-spring-cloud</artifactId>
|
||||
<groupId>org.apache.skywalking</groupId>
|
||||
<version>9.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>apm-spring-cloud-gateway-4.x-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<properties>
|
||||
<spring-cloud-starter-gateway.version>4.0.0</spring-cloud-starter-gateway.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
<version>${spring-cloud-starter-gateway.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.skywalking</groupId>
|
||||
<artifactId>apm-spring-webflux-6.x-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>org.apache.skywalking:apm-spring-webflux-6.x-plugin</artifact>
|
||||
<excludes>
|
||||
<exclude>skywalking-plugin.def</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x;
|
||||
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
|
||||
import reactor.netty.http.client.HttpClientConfig;
|
||||
|
||||
/**
|
||||
* Intercept the constructor and inject {@link EnhanceObjectCache}.
|
||||
* <p>
|
||||
* The first constructor argument is {@link reactor.netty.http.client.HttpClientConfig} class instance which can get the
|
||||
* request uri string.
|
||||
*/
|
||||
public class HttpClientFinalizerConstructorInterceptor implements InstanceConstructorInterceptor {
|
||||
|
||||
@Override
|
||||
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
|
||||
final HttpClientConfig httpClientConfig = (HttpClientConfig) allArguments[0];
|
||||
if (httpClientConfig == null) {
|
||||
return;
|
||||
}
|
||||
final EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
|
||||
enhanceObjectCache.setUrl(httpClientConfig.uri());
|
||||
objInst.setSkyWalkingDynamicField(enhanceObjectCache);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x;
|
||||
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.SignalType;
|
||||
import reactor.netty.Connection;
|
||||
import reactor.netty.http.client.HttpClientResponse;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* This class intercept <code>responseConnection</code> method.
|
||||
* <p>
|
||||
* After downstream service response, finish the span in the {@link EnhanceObjectCache}.
|
||||
*/
|
||||
public class HttpClientFinalizerResponseConnectionInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) {
|
||||
BiFunction<? super HttpClientResponse, ? super Connection, ? extends Publisher> finalReceiver = (BiFunction<? super HttpClientResponse, ? super Connection, ? extends Publisher>) allArguments[0];
|
||||
EnhanceObjectCache cache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
|
||||
allArguments[0] = (BiFunction<HttpClientResponse, Connection, Publisher>) (response, connection) -> {
|
||||
Publisher publisher = finalReceiver.apply(response, connection);
|
||||
if (cache == null) {
|
||||
return publisher;
|
||||
}
|
||||
// receive the response.
|
||||
if (cache.getSpan() != null) {
|
||||
if (response.status().code() >= HttpResponseStatus.BAD_REQUEST.code()) {
|
||||
cache.getSpan().errorOccurred();
|
||||
}
|
||||
Tags.HTTP_RESPONSE_STATUS_CODE.set(cache.getSpan(), response.status().code());
|
||||
}
|
||||
|
||||
return publisher;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
Object ret) {
|
||||
Flux<?> responseFlux = (Flux<?>) ret;
|
||||
|
||||
responseFlux = responseFlux
|
||||
.doOnError(e -> {
|
||||
EnhanceObjectCache cache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
|
||||
if (cache == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cache.getSpan() != null) {
|
||||
cache.getSpan().errorOccurred();
|
||||
cache.getSpan().log(e);
|
||||
}
|
||||
})
|
||||
.doFinally(signalType -> {
|
||||
EnhanceObjectCache cache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
|
||||
if (cache == null) {
|
||||
return;
|
||||
}
|
||||
// do finally. Finish the span.
|
||||
if (cache.getSpan() != null) {
|
||||
if (signalType == SignalType.CANCEL) {
|
||||
cache.getSpan().errorOccurred();
|
||||
}
|
||||
cache.getSpan().asyncFinish();
|
||||
}
|
||||
|
||||
if (cache.getSpan1() != null) {
|
||||
cache.getSpan1().asyncFinish();
|
||||
}
|
||||
});
|
||||
|
||||
return responseFlux;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x;
|
||||
|
||||
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
|
||||
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
import org.apache.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
|
||||
import org.apache.skywalking.apm.util.StringUtil;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.netty.NettyOutbound;
|
||||
import reactor.netty.http.client.HttpClientRequest;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.SPRING_CLOUD_GATEWAY;
|
||||
|
||||
/**
|
||||
* This class intercept <code>send</code> method.
|
||||
* <p>
|
||||
* In before method, create a new BiFunction lambda expression for setting <code>ContextCarrier</code> to http header
|
||||
* and replace the original lambda in argument
|
||||
*/
|
||||
public class HttpClientFinalizerSendInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
EnhanceObjectCache enhanceObjectCache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
|
||||
if (enhanceObjectCache == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
In this plug-in, the HttpClientFinalizerSendInterceptor depends on the NettyRoutingFilterInterceptor
|
||||
When the NettyRoutingFilterInterceptor is not executed, the HttpClientFinalizerSendInterceptor has no meaning to be executed independently
|
||||
and using ContextManager.activeSpan() method would cause NPE as active span does not exist.
|
||||
*/
|
||||
if (!ContextManager.isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AbstractSpan span = ContextManager.activeSpan();
|
||||
span.prepareForAsync();
|
||||
|
||||
if (StringUtil.isNotEmpty(enhanceObjectCache.getUrl())) {
|
||||
URL url = new URL(enhanceObjectCache.getUrl());
|
||||
|
||||
ContextCarrier contextCarrier = new ContextCarrier();
|
||||
AbstractSpan abstractSpan = ContextManager.createExitSpan(
|
||||
"SpringCloudGateway/sendRequest", contextCarrier, getPeer(url));
|
||||
Tags.URL.set(abstractSpan, enhanceObjectCache.getUrl());
|
||||
abstractSpan.prepareForAsync();
|
||||
abstractSpan.setComponent(SPRING_CLOUD_GATEWAY);
|
||||
abstractSpan.setLayer(SpanLayer.HTTP);
|
||||
ContextManager.stopSpan(abstractSpan);
|
||||
|
||||
BiFunction<? super HttpClientRequest, ? super NettyOutbound, ? extends Publisher<Void>> finalSender = (BiFunction<? super HttpClientRequest, ? super NettyOutbound, ? extends Publisher<Void>>) allArguments[0];
|
||||
allArguments[0] = (BiFunction<HttpClientRequest, NettyOutbound, Publisher<Void>>) (request, outbound) -> {
|
||||
Publisher publisher = finalSender.apply(request, outbound);
|
||||
|
||||
CarrierItem next = contextCarrier.items();
|
||||
while (next.hasNext()) {
|
||||
next = next.next();
|
||||
request.requestHeaders().remove(next.getHeadKey());
|
||||
request.requestHeaders().set(next.getHeadKey(), next.getHeadValue());
|
||||
}
|
||||
return publisher;
|
||||
};
|
||||
enhanceObjectCache.setCacheSpan(abstractSpan);
|
||||
}
|
||||
ContextManager.stopSpan(span);
|
||||
enhanceObjectCache.setSpan1(span);
|
||||
}
|
||||
|
||||
private String getPeer(URL url) {
|
||||
return url.getHost() + ":" + url.getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
Object ret) {
|
||||
((EnhancedInstance) ret).setSkyWalkingDynamicField(objInst.getSkyWalkingDynamicField());
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x;
|
||||
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* This class intercept <code>uri</code> method to get the url of downstream service
|
||||
*/
|
||||
public class HttpClientFinalizerUriInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
Object ret) throws Throwable {
|
||||
if (ret instanceof EnhancedInstance) {
|
||||
EnhanceObjectCache enhanceObjectCache = (EnhanceObjectCache) ((EnhancedInstance) ret)
|
||||
.getSkyWalkingDynamicField();
|
||||
enhanceObjectCache.setUrl(String.valueOf(allArguments[0]));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x;
|
||||
|
||||
import org.apache.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebExchangeDecorator;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.SPRING_CLOUD_GATEWAY;
|
||||
|
||||
/**
|
||||
* This class intercept <code>filter</code> method.
|
||||
* <p>
|
||||
* <code>spring-webflux-5.x-plugin</code> will inject context snapshot into skywalking dynamic field, and this
|
||||
* interceptor will continue the span in another thread.
|
||||
* </p>
|
||||
*/
|
||||
public class NettyRoutingFilterInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
private static final String NETTY_ROUTING_FILTER_TRACED_ATTR = NettyRoutingFilterInterceptor.class.getName() + ".isTraced";
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
|
||||
if (isTraced(exchange)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTracedStatus(exchange);
|
||||
|
||||
EnhancedInstance enhancedInstance = getInstance(allArguments[0]);
|
||||
|
||||
AbstractSpan span = ContextManager.createLocalSpan("SpringCloudGateway/RoutingFilter");
|
||||
if (enhancedInstance != null && enhancedInstance.getSkyWalkingDynamicField() != null) {
|
||||
ContextManager.continued((ContextSnapshot) enhancedInstance.getSkyWalkingDynamicField());
|
||||
}
|
||||
span.setComponent(SPRING_CLOUD_GATEWAY);
|
||||
}
|
||||
|
||||
private static void setTracedStatus(ServerWebExchange exchange) {
|
||||
exchange.getAttributes().put(NETTY_ROUTING_FILTER_TRACED_ATTR, true);
|
||||
}
|
||||
|
||||
private static boolean isTraced(ServerWebExchange exchange) {
|
||||
return exchange.getAttributeOrDefault(NETTY_ROUTING_FILTER_TRACED_ATTR, false);
|
||||
}
|
||||
|
||||
private EnhancedInstance getInstance(Object o) {
|
||||
EnhancedInstance instance = null;
|
||||
if (o instanceof EnhancedInstance) {
|
||||
instance = (EnhancedInstance) o;
|
||||
} else if (o instanceof ServerWebExchangeDecorator) {
|
||||
ServerWebExchange delegate = ((ServerWebExchangeDecorator) o).getDelegate();
|
||||
return getInstance(delegate);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
Object ret) throws Throwable {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
ContextManager.activeSpan().log(t);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define;
|
||||
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
|
||||
/**
|
||||
* This abstract class defines the <code>witnessClasses()</code> method,
|
||||
* and other plugin define classes need to inherit from this class
|
||||
*/
|
||||
public abstract class AbstractGatewayV4EnhancePluginDefine extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
|
||||
/**
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@Override
|
||||
protected String[] witnessClasses() {
|
||||
return new String[]{"org.springframework.cloud.gateway.filter.factory.cache.LocalResponseCacheProperties"};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define;
|
||||
|
||||
/**
|
||||
* This class is used for enable {@link org.apache.skywalking.apm.plugin.spring.webflux.v6.define.DispatcherHandlerInstrumentation}
|
||||
* class when {@link org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties} class is exist
|
||||
*/
|
||||
public class DispatcherHandlerInstrumentation extends
|
||||
org.apache.skywalking.apm.plugin.spring.webflux.v6.define.DispatcherHandlerInstrumentation {
|
||||
|
||||
/**
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@Override
|
||||
protected String[] witnessClasses() {
|
||||
return new String[]{"org.springframework.cloud.gateway.filter.factory.cache.LocalResponseCacheProperties"};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define;
|
||||
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
|
||||
/**
|
||||
* enhance object cache
|
||||
*/
|
||||
public class EnhanceObjectCache {
|
||||
|
||||
private String url;
|
||||
private AbstractSpan span;
|
||||
private AbstractSpan span1;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public void setCacheSpan(AbstractSpan span) {
|
||||
this.span = span;
|
||||
}
|
||||
|
||||
public AbstractSpan getSpan() {
|
||||
return span;
|
||||
}
|
||||
|
||||
public AbstractSpan getSpan1() {
|
||||
return span1;
|
||||
}
|
||||
|
||||
public void setSpan1(final AbstractSpan span) {
|
||||
span1 = span;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
|
||||
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
|
||||
|
||||
/**
|
||||
* This class instrument <code>reactor.netty.http.client.HttpClientFinalizer</code> class.
|
||||
* <p>
|
||||
* This is the class that actually sends the request. By enhancing in different methods,
|
||||
* we can get information such as uri and send trace context to the downstream service through http header.
|
||||
* </p>
|
||||
*/
|
||||
public class HttpClientFinalizerInstrumentation extends AbstractGatewayV4EnhancePluginDefine {
|
||||
|
||||
private static final String INTERCEPT_CLASS_HTTP_CLIENT_FINALIZER = "reactor.netty.http.client.HttpClientFinalizer";
|
||||
private static final String CLIENT_FINALIZER_CONSTRUCTOR_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.HttpClientFinalizerConstructorInterceptor";
|
||||
private static final String CLIENT_FINALIZER_CONSTRUCTOR_ARGUMENT_TYPE = "reactor.netty.http.client.HttpClientConfig";
|
||||
private static final String HTTP_CLIENT_FINALIZER_URI_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.HttpClientFinalizerUriInterceptor";
|
||||
private static final String HTTP_CLIENT_FINALIZER_SEND_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.HttpClientFinalizerSendInterceptor";
|
||||
private static final String HTTP_CLIENT_FINALIZER_RESPONSE_CONNECTION_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.HttpClientFinalizerResponseConnectionInterceptor";
|
||||
|
||||
@Override
|
||||
protected ClassMatch enhanceClass() {
|
||||
return byName(INTERCEPT_CLASS_HTTP_CLIENT_FINALIZER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[]{
|
||||
new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return takesArgumentWithType(0, CLIENT_FINALIZER_CONSTRUCTOR_ARGUMENT_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return CLIENT_FINALIZER_CONSTRUCTOR_INTERCEPTOR;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("uri");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return HTTP_CLIENT_FINALIZER_URI_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("send").and(takesArgumentWithType(0, "java.util.function.BiFunction"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return HTTP_CLIENT_FINALIZER_SEND_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverrideArgs() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("responseConnection");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return HTTP_CLIENT_FINALIZER_RESPONSE_CONNECTION_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverrideArgs() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
|
||||
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
|
||||
|
||||
/**
|
||||
* This class instrument {@link org.springframework.cloud.gateway.filter.NettyRoutingFilter} class.
|
||||
* <p>
|
||||
* Enhance <code>filter</code> method and get <code>ContextSnapshot</code> from {@link
|
||||
* org.springframework.web.server.ServerWebExchange}. Create a local span to continue context snapshot created in {@link
|
||||
* org.apache.skywalking.apm.plugin.spring.webflux.v6.DispatcherHandlerHandleMethodInterceptor} interceptor.
|
||||
* </p>
|
||||
*/
|
||||
public class NettyRoutingFilterInstrumentation extends AbstractGatewayV4EnhancePluginDefine {
|
||||
|
||||
private static final String INTERCEPT_CLASS_NETTY_ROUTING_FILTER = "org.springframework.cloud.gateway.filter.NettyRoutingFilter";
|
||||
private static final String NETTY_ROUTING_FILTER_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.NettyRoutingFilterInterceptor";
|
||||
|
||||
@Override
|
||||
protected ClassMatch enhanceClass() {
|
||||
return byName(INTERCEPT_CLASS_NETTY_ROUTING_FILTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[]{
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("filter").and(
|
||||
takesArgumentWithType(0, "org.springframework.web.server.ServerWebExchange"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return NETTY_ROUTING_FILTER_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverrideArgs() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define;
|
||||
|
||||
/**
|
||||
* This class is used for enable {@link org.apache.skywalking.apm.plugin.spring.webflux.v6.define.ServerWebExchangeInstrumentation}
|
||||
* when {@link org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties} class is exist.
|
||||
*/
|
||||
public class ServerWebExchangeInstrumentation extends
|
||||
org.apache.skywalking.apm.plugin.spring.webflux.v6.define.ServerWebExchangeInstrumentation {
|
||||
|
||||
/**
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@Override
|
||||
protected String[] witnessClasses() {
|
||||
return new String[]{"org.springframework.cloud.gateway.filter.factory.cache.LocalResponseCacheProperties"};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.HttpClientFinalizerInstrumentation
|
||||
spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.NettyRoutingFilterInstrumentation
|
||||
spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.ServerWebExchangeInstrumentation
|
||||
spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.DispatcherHandlerInstrumentation
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import reactor.netty.http.client.HttpClientConfig;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class HttpClientFinalizerConstructorInterceptorTest {
|
||||
|
||||
private static final String URI = "http://localhost:8080/get";
|
||||
private final EnhancedInstance enhancedInstance = new EnhancedInstance() {
|
||||
private EnhanceObjectCache enhanceObjectCache;
|
||||
|
||||
@Override
|
||||
public Object getSkyWalkingDynamicField() {
|
||||
return enhanceObjectCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyWalkingDynamicField(Object value) {
|
||||
this.enhanceObjectCache = (EnhanceObjectCache) value;
|
||||
}
|
||||
};
|
||||
private HttpClientConfig httpClientConfig;
|
||||
private HttpClientFinalizerConstructorInterceptor httpClientFinalizerConstructorInterceptor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
httpClientConfig = mock(HttpClientConfig.class);
|
||||
when(httpClientConfig.uri()).thenReturn(URI);
|
||||
httpClientFinalizerConstructorInterceptor = new HttpClientFinalizerConstructorInterceptor();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onConstruct() {
|
||||
httpClientFinalizerConstructorInterceptor.onConstruct(enhancedInstance, new Object[]{httpClientConfig});
|
||||
final EnhanceObjectCache enhanceCache = (EnhanceObjectCache) enhancedInstance.getSkyWalkingDynamicField();
|
||||
assertNotNull(enhanceCache);
|
||||
assertEquals(enhanceCache.getUrl(), URI);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import org.apache.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
|
||||
import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
|
||||
import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
|
||||
import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
|
||||
import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
|
||||
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
|
||||
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
import org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.EnhanceObjectCache;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
import org.reactivestreams.Publisher;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.netty.Connection;
|
||||
import reactor.netty.NettyOutbound;
|
||||
import reactor.netty.http.client.HttpClientRequest;
|
||||
import reactor.netty.http.client.HttpClientResponse;
|
||||
|
||||
@RunWith(TracingSegmentRunner.class)
|
||||
public class HttpClientFinalizerInterceptorTest {
|
||||
|
||||
private final static String URI = "http://localhost:8080/get";
|
||||
private final static String ENTRY_OPERATION_NAME = "/get";
|
||||
private final HttpClientFinalizerSendInterceptor sendInterceptor = new HttpClientFinalizerSendInterceptor();
|
||||
private final HttpClientFinalizerResponseConnectionInterceptor responseConnectionInterceptor = new HttpClientFinalizerResponseConnectionInterceptor();
|
||||
private final BiFunction<? super HttpClientRequest, ? super NettyOutbound, ? extends Publisher<Void>> originalSendBiFunction = (httpClientRequest, nettyOutbound) -> (Publisher<Void>) s -> {
|
||||
};
|
||||
private final BiFunction<? super HttpClientResponse, ? super Connection, ? extends Publisher<Void>> originalResponseConnectionBiFunction = (httpClientResponse, connection) -> (Publisher<Void>) s -> {
|
||||
};
|
||||
private final EnhancedInstance enhancedInstance = new EnhancedInstance() {
|
||||
private EnhanceObjectCache enhanceObjectCache;
|
||||
|
||||
@Override
|
||||
public Object getSkyWalkingDynamicField() {
|
||||
return enhanceObjectCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyWalkingDynamicField(Object value) {
|
||||
this.enhanceObjectCache = (EnhanceObjectCache) value;
|
||||
}
|
||||
};
|
||||
@Rule
|
||||
public AgentServiceRule serviceRule = new AgentServiceRule();
|
||||
@Rule
|
||||
public MockitoRule rule = MockitoJUnit.rule();
|
||||
|
||||
private HttpClientResponse mockResponse;
|
||||
private HttpClientRequest mockRequest;
|
||||
@SegmentStoragePoint
|
||||
private SegmentStorage segmentStorage;
|
||||
private AbstractSpan entrySpan;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
|
||||
enhanceObjectCache.setUrl(URI);
|
||||
enhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
|
||||
entrySpan = ContextManager.createEntrySpan(ENTRY_OPERATION_NAME, null);
|
||||
entrySpan.setLayer(SpanLayer.HTTP);
|
||||
entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
|
||||
mockRequest = new MockCliengRequest();
|
||||
mockResponse = new MockClientResponse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithDynamicFieldNull() throws Throwable {
|
||||
enhancedInstance.setSkyWalkingDynamicField(null);
|
||||
executeSendRequest();
|
||||
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
|
||||
assertEquals(traceSegments.size(), 0);
|
||||
if (ContextManager.isActive()) {
|
||||
ContextManager.stopSpan();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithEmptyUri() throws Throwable {
|
||||
final EnhanceObjectCache objectCache = (EnhanceObjectCache) enhancedInstance.getSkyWalkingDynamicField();
|
||||
objectCache.setUrl("");
|
||||
executeSendRequest();
|
||||
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
|
||||
assertEquals(traceSegments.size(), 1);
|
||||
final List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegments.get(0));
|
||||
assertNotNull(spans);
|
||||
assertEquals(spans.size(), 1);
|
||||
assertUpstreamSpan(spans.get(0));
|
||||
assertNotNull(objectCache.getSpan1());
|
||||
assertEquals(objectCache.getSpan1().getSpanId(), entrySpan.getSpanId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithUri() throws Throwable {
|
||||
executeSendRequest();
|
||||
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
|
||||
assertEquals(traceSegments.size(), 1);
|
||||
final EnhanceObjectCache objectCache = (EnhanceObjectCache) enhancedInstance
|
||||
.getSkyWalkingDynamicField();
|
||||
assertNotNull(objectCache.getSpan1());
|
||||
assertNotNull(objectCache.getSpan());
|
||||
assertEquals(objectCache.getSpan1().getSpanId(), entrySpan.getSpanId());
|
||||
assertTrue(objectCache.getSpan().isExit());
|
||||
assertEquals(objectCache.getSpan().getOperationName(), "SpringCloudGateway/sendRequest");
|
||||
final List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegments.get(0));
|
||||
assertNotNull(spans);
|
||||
assertEquals(spans.size(), 2);
|
||||
assertUpstreamSpan(spans.get(1));
|
||||
assertDownstreamSpan(spans.get(0));
|
||||
}
|
||||
|
||||
private void executeSendRequest() throws Throwable {
|
||||
Object[] sendArguments = new Object[]{originalSendBiFunction};
|
||||
sendInterceptor.beforeMethod(enhancedInstance, null, sendArguments, null, null);
|
||||
sendInterceptor.afterMethod(enhancedInstance, null, new Object[0], null, enhancedInstance);
|
||||
((BiFunction<? super HttpClientRequest, ? super NettyOutbound, ? extends Publisher<Void>>) sendArguments[0])
|
||||
.apply(mockRequest, null);
|
||||
Object[] responseConnectionArguments = new Object[]{originalResponseConnectionBiFunction};
|
||||
responseConnectionInterceptor
|
||||
.beforeMethod(enhancedInstance, null, responseConnectionArguments, null, null);
|
||||
Flux flux = Flux.just(0);
|
||||
|
||||
flux = (Flux) responseConnectionInterceptor.afterMethod(enhancedInstance, null, new Object[0], null, flux);
|
||||
|
||||
((BiFunction<? super HttpClientResponse, ? super Connection, ? extends Publisher<Void>>) responseConnectionArguments[0])
|
||||
.apply(mockResponse, null);
|
||||
flux.blockFirst();
|
||||
}
|
||||
|
||||
private void assertUpstreamSpan(AbstractSpan span) {
|
||||
SpanAssert.assertLayer(span, SpanLayer.HTTP);
|
||||
SpanAssert.assertComponent(span, ComponentsDefine.SPRING_WEBFLUX);
|
||||
}
|
||||
|
||||
private void assertDownstreamSpan(AbstractSpan span) {
|
||||
SpanAssert.assertLayer(span, SpanLayer.HTTP);
|
||||
SpanAssert.assertComponent(span, ComponentsDefine.SPRING_CLOUD_GATEWAY);
|
||||
SpanAssert.assertTagSize(span, 2);
|
||||
SpanAssert.assertTag(span, 0, URI);
|
||||
SpanAssert.assertTag(span, 1, String.valueOf(HttpResponseStatus.OK.code()));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x;
|
||||
|
||||
import io.netty.handler.codec.http.DefaultHttpHeaders;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http.cookie.Cookie;
|
||||
import reactor.netty.http.client.HttpClientRequest;
|
||||
import reactor.util.context.Context;
|
||||
import reactor.util.context.ContextView;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class MockCliengRequest implements HttpClientRequest {
|
||||
|
||||
@Override
|
||||
public HttpClientRequest addCookie(Cookie cookie) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClientRequest addHeader(CharSequence charSequence, CharSequence charSequence1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClientRequest header(CharSequence charSequence, CharSequence charSequence1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClientRequest headers(HttpHeaders httpHeaders) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFollowRedirect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClientRequest responseTimeout(Duration duration) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context currentContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextView currentContextView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] redirectedFrom() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders requestHeaders() {
|
||||
return new DefaultHttpHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resourceUrl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<CharSequence, Set<Cookie>> cookies() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isKeepAlive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWebsocket() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpMethod method() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path() {
|
||||
return HttpClientRequest.super.path();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fullPath() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String requestId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uri() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpVersion version() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x;
|
||||
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http.cookie.Cookie;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.netty.http.client.HttpClientResponse;
|
||||
import reactor.util.context.Context;
|
||||
import reactor.util.context.ContextView;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class MockClientResponse implements HttpClientResponse {
|
||||
|
||||
@Override
|
||||
public HttpHeaders responseHeaders() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponseStatus status() {
|
||||
return HttpResponseStatus.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<HttpHeaders> trailerHeaders() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context currentContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextView currentContextView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] redirectedFrom() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders requestHeaders() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resourceUrl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<CharSequence, Set<Cookie>> cookies() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isKeepAlive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWebsocket() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpMethod method() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String path() {
|
||||
return HttpClientResponse.super.path();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fullPath() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String requestId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uri() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpVersion version() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import org.apache.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
|
||||
import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
|
||||
import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
|
||||
import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
|
||||
import org.apache.skywalking.apm.agent.test.tools.SpanAssert;
|
||||
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
|
||||
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.i18n.LocaleContext;
|
||||
import org.springframework.http.codec.multipart.Part;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebSession;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@RunWith(TracingSegmentRunner.class)
|
||||
public class NettyRoutingFilterInterceptorTest {
|
||||
private static class ServerWebExchangeEnhancedInstance implements ServerWebExchange, EnhancedInstance {
|
||||
private ContextSnapshot snapshot;
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Object getSkyWalkingDynamicField() {
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyWalkingDynamicField(Object value) {
|
||||
this.snapshot = (ContextSnapshot) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerHttpRequest getRequest() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerHttpResponse getResponse() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<WebSession> getSession() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Principal> Mono<T> getPrincipal() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<MultiValueMap<String, String>> getFormData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<MultiValueMap<String, Part>> getMultipartData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocaleContext getLocaleContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationContext getApplicationContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNotModified() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkNotModified(Instant instant) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkNotModified(String s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkNotModified(String s, Instant instant) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String transformUrl(String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addUrlTransformer(Function<String, String> function) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLogPrefix() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private final ServerWebExchangeEnhancedInstance enhancedInstance = new ServerWebExchangeEnhancedInstance();
|
||||
private final NettyRoutingFilterInterceptor interceptor = new NettyRoutingFilterInterceptor();
|
||||
@Rule
|
||||
public AgentServiceRule serviceRule = new AgentServiceRule();
|
||||
@Rule
|
||||
public MockitoRule rule = MockitoJUnit.rule();
|
||||
|
||||
@SegmentStoragePoint
|
||||
private SegmentStorage segmentStorage;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithNullDynamicField() throws Throwable {
|
||||
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
|
||||
interceptor.afterMethod(null, null, null, null, null);
|
||||
ContextManager.stopSpan();
|
||||
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
|
||||
Assert.assertEquals(traceSegments.size(), 1);
|
||||
final List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegments.get(0));
|
||||
Assert.assertNotNull(spans);
|
||||
Assert.assertEquals(spans.size(), 1);
|
||||
SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithContextSnapshot() throws Throwable {
|
||||
final AbstractSpan entrySpan = ContextManager.createEntrySpan("/get", null);
|
||||
SpanLayer.asHttp(entrySpan);
|
||||
entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
|
||||
enhancedInstance.setSkyWalkingDynamicField(ContextManager.capture());
|
||||
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
|
||||
interceptor.afterMethod(null, null, null, null, null);
|
||||
ContextManager.stopSpan();
|
||||
ContextManager.stopSpan(entrySpan);
|
||||
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
|
||||
Assert.assertEquals(traceSegments.size(), 1);
|
||||
final List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegments.get(0));
|
||||
Assert.assertNotNull(spans);
|
||||
Assert.assertEquals(spans.size(), 2);
|
||||
SpanAssert.assertComponent(spans.get(0), ComponentsDefine.SPRING_CLOUD_GATEWAY);
|
||||
SpanAssert.assertComponent(spans.get(1), ComponentsDefine.SPRING_WEBFLUX);
|
||||
SpanAssert.assertLayer(spans.get(1), SpanLayer.HTTP);
|
||||
}
|
||||
|
||||
private static final String NETTY_ROUTING_FILTER_TRACED_ATTR =
|
||||
NettyRoutingFilterInterceptor.class.getName() + ".isTraced";
|
||||
|
||||
@Test
|
||||
public void testIsTraced() throws Throwable {
|
||||
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
|
||||
interceptor.afterMethod(null, null, null, null, null);
|
||||
Assert.assertEquals(enhancedInstance.getAttributes().get(NETTY_ROUTING_FILTER_TRACED_ATTR), true);
|
||||
Assert.assertNotNull(ContextManager.activeSpan());
|
||||
|
||||
ContextManager.stopSpan();
|
||||
|
||||
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
|
||||
interceptor.afterMethod(null, null, null, null, null);
|
||||
Assert.assertEquals(enhancedInstance.getAttributes().get(NETTY_ROUTING_FILTER_TRACED_ATTR), true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
mock-maker-inline
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
<module>gateway-2.0.x-plugin</module>
|
||||
<module>gateway-2.1.x-plugin</module>
|
||||
<module>gateway-3.x-plugin</module>
|
||||
<module>gateway-4.x-plugin</module>
|
||||
</modules>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
<module>spring-webflux-5.x-plugin</module>
|
||||
<module>resttemplate-6.x-plugin</module>
|
||||
<module>mvc-annotation-6.x-plugin</module>
|
||||
<module>spring-webflux-6.x-plugin</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
|
|
|||
|
|
@ -18,8 +18,11 @@
|
|||
|
||||
package org.apache.skywalking.apm.plugin.spring.webflux.v5.define;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
|
|
@ -29,6 +32,9 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
|
||||
|
||||
public class DispatcherHandlerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
private static final String WEBFLUX_CONTEXT_WRITE_CLASS = "reactor.core.publisher.Mono";
|
||||
private static final String WEBFLUX_CONTEXT_WRITE_METHOD = "subscriberContext";
|
||||
|
||||
@Override
|
||||
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[0];
|
||||
|
|
@ -60,4 +66,10 @@ public class DispatcherHandlerInstrumentation extends ClassInstanceMethodsEnhanc
|
|||
protected ClassMatch enhanceClass() {
|
||||
return byName("org.springframework.web.reactive.DispatcherHandler");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<WitnessMethod> witnessMethods() {
|
||||
return Collections.singletonList(
|
||||
new WitnessMethod(WEBFLUX_CONTEXT_WRITE_CLASS, named(WEBFLUX_CONTEXT_WRITE_METHOD)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>optional-spring-plugins</artifactId>
|
||||
<groupId>org.apache.skywalking</groupId>
|
||||
<version>9.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>apm-spring-webflux-6.x-plugin</artifactId>
|
||||
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webflux</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.webflux.v6;
|
||||
|
||||
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
|
||||
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
|
||||
import org.apache.skywalking.apm.agent.core.context.ContextManager;
|
||||
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
|
||||
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
|
||||
import org.apache.skywalking.apm.agent.core.context.tag.Tags.HTTP;
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
|
||||
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
|
||||
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebExchangeDecorator;
|
||||
import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
public class DispatcherHandlerHandleMethodInterceptor implements InstanceMethodsAroundInterceptor {
|
||||
|
||||
@Override
|
||||
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
MethodInterceptResult result) throws Throwable {
|
||||
EnhancedInstance instance = getInstance(allArguments[0]);
|
||||
|
||||
ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
|
||||
|
||||
ContextCarrier carrier = new ContextCarrier();
|
||||
CarrierItem next = carrier.items();
|
||||
HttpHeaders headers = exchange.getRequest().getHeaders();
|
||||
while (next.hasNext()) {
|
||||
next = next.next();
|
||||
List<String> header = headers.get(next.getHeadKey());
|
||||
if (header != null && header.size() > 0) {
|
||||
next.setHeadValue(header.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
AbstractSpan span = ContextManager.createEntrySpan(exchange.getRequest().getURI().getPath(), carrier);
|
||||
|
||||
if (instance != null && instance.getSkyWalkingDynamicField() != null) {
|
||||
ContextManager.continued((ContextSnapshot) instance.getSkyWalkingDynamicField());
|
||||
}
|
||||
span.setComponent(ComponentsDefine.SPRING_WEBFLUX);
|
||||
SpanLayer.asHttp(span);
|
||||
Tags.URL.set(span, exchange.getRequest().getURI().toString());
|
||||
HTTP.METHOD.set(span, exchange.getRequest().getMethod().name());
|
||||
instance.setSkyWalkingDynamicField(ContextManager.capture());
|
||||
span.prepareForAsync();
|
||||
ContextManager.stopSpan(span);
|
||||
|
||||
exchange.getAttributes().put("SKYWALKING_SPAN", span);
|
||||
}
|
||||
|
||||
private void maybeSetPattern(AbstractSpan span, ServerWebExchange exchange) {
|
||||
if (span != null) {
|
||||
PathPattern pathPattern = exchange.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
|
||||
//check if the best matching pattern matches url in request
|
||||
//to avoid operationName overwritten by fallback url
|
||||
if (pathPattern != null && pathPattern.matches(exchange.getRequest().getPath().pathWithinApplication())) {
|
||||
span.setOperationName(pathPattern.getPatternString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
|
||||
Object ret) throws Throwable {
|
||||
|
||||
ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
|
||||
|
||||
AbstractSpan span = (AbstractSpan) exchange.getAttributes().get("SKYWALKING_SPAN");
|
||||
Mono<Void> monoReturn = (Mono<Void>) ret;
|
||||
|
||||
// add skywalking context snapshot to reactor context.
|
||||
EnhancedInstance instance = getInstance(allArguments[0]);
|
||||
if (instance != null && instance.getSkyWalkingDynamicField() != null) {
|
||||
monoReturn = monoReturn.contextWrite(
|
||||
c -> c.put("SKYWALKING_CONTEXT_SNAPSHOT", instance.getSkyWalkingDynamicField()));
|
||||
}
|
||||
|
||||
return monoReturn.doFinally(s -> {
|
||||
|
||||
if (span != null) {
|
||||
maybeSetPattern(span, exchange);
|
||||
try {
|
||||
|
||||
HttpStatusCode httpStatus = exchange.getResponse().getStatusCode();
|
||||
// fix webflux-2.0.0-2.1.0 version have bug. httpStatus is null. not support
|
||||
if (httpStatus != null) {
|
||||
Tags.HTTP_RESPONSE_STATUS_CODE.set(span, httpStatus.value());
|
||||
if (httpStatus.isError()) {
|
||||
span.errorOccurred();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
span.asyncFinish();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
|
||||
Class<?>[] argumentsTypes, Throwable t) {
|
||||
}
|
||||
|
||||
public static EnhancedInstance getInstance(Object o) {
|
||||
EnhancedInstance instance = null;
|
||||
if (o instanceof DefaultServerWebExchange) {
|
||||
instance = (EnhancedInstance) o;
|
||||
} else if (o instanceof ServerWebExchangeDecorator) {
|
||||
ServerWebExchange delegate = ((ServerWebExchangeDecorator) o).getDelegate();
|
||||
return getInstance(delegate);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.webflux.v6;
|
||||
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
|
||||
|
||||
public class ServerWebExchangeConstructorInterceptor implements InstanceConstructorInterceptor {
|
||||
@Override
|
||||
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.webflux.v6.define;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
|
||||
|
||||
public class DispatcherHandlerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
private static final String WEBFLUX_CONTEXT_WRITE_CLASS = "reactor.core.publisher.Mono";
|
||||
private static final String WEBFLUX_CONTEXT_WRITE_METHOD = "contextWrite";
|
||||
private static final String WEBFLUX_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.webflux.v6.DispatcherHandlerHandleMethodInterceptor";
|
||||
private static final String WEBFLUX_ENHANCE_CLASS = "org.springframework.web.reactive.DispatcherHandler";
|
||||
|
||||
@Override
|
||||
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[] {
|
||||
new InstanceMethodsInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getMethodsMatcher() {
|
||||
return named("handle");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodsInterceptor() {
|
||||
return WEBFLUX_METHOD_INTERCEPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverrideArgs() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassMatch enhanceClass() {
|
||||
return byName(WEBFLUX_ENHANCE_CLASS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 6.0.0
|
||||
*/
|
||||
@Override
|
||||
protected List<WitnessMethod> witnessMethods() {
|
||||
return Collections.singletonList(
|
||||
new WitnessMethod(WEBFLUX_CONTEXT_WRITE_CLASS, named(WEBFLUX_CONTEXT_WRITE_METHOD)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.skywalking.apm.plugin.spring.webflux.v6.define;
|
||||
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
|
||||
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.any;
|
||||
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
|
||||
|
||||
public class ServerWebExchangeInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
|
||||
private static final String WEBFLUX_CONSTRUCTOR_INTERCEPOR = "org.apache.skywalking.apm.plugin.spring.webflux.v6.ServerWebExchangeConstructorInterceptor";
|
||||
private static final String WEBFLUX_ENHANCE_CLASS = "org.springframework.web.server.adapter.DefaultServerWebExchange";
|
||||
|
||||
@Override
|
||||
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
|
||||
return new ConstructorInterceptPoint[] {
|
||||
new ConstructorInterceptPoint() {
|
||||
@Override
|
||||
public ElementMatcher<MethodDescription> getConstructorMatcher() {
|
||||
return any();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConstructorInterceptor() {
|
||||
return WEBFLUX_CONSTRUCTOR_INTERCEPOR;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
|
||||
return new InstanceMethodsInterceptPoint[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassMatch enhanceClass() {
|
||||
return byName(WEBFLUX_ENHANCE_CLASS);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
spring-webflux-6.x=org.apache.skywalking.apm.plugin.spring.webflux.v6.define.DispatcherHandlerInstrumentation
|
||||
spring-webflux-6.x=org.apache.skywalking.apm.plugin.spring.webflux.v6.define.ServerWebExchangeInstrumentation
|
||||
|
|
@ -9,7 +9,7 @@ Now, we have the following known optional plugins.
|
|||
* Plugin of Gson serialization lib in optional plugin folder.
|
||||
* Plugin of Zookeeper 3.4.x in optional plugin folder. The reason of being optional plugin is, many business irrelevant traces are generated, which cause extra payload to agents and backends. At the same time, those traces may be just heartbeat(s).
|
||||
* [Customize enhance](Customize-enhance-trace.md) Trace methods based on description files, rather than write plugin or change source codes.
|
||||
* Plugin of Spring Cloud Gateway 2.x and 3.x in optional plugin folder. Please only activate this plugin when you install agent in Spring Gateway.
|
||||
* Plugin of Spring Cloud Gateway 2.x and 3.x and 4.x in optional plugin folder. Please only activate this plugin when you install agent in Spring Gateway.
|
||||
* Plugin of Spring Transaction in optional plugin folder. The reason of being optional plugin is, many local span are generated, which also spend more CPU, memory and network.
|
||||
* [Plugin of Kotlin coroutine](agent-optional-plugins/Kotlin-Coroutine-plugin.md) provides the tracing across coroutines automatically. As it will add local spans to all across routines scenarios, Please assess the performance impact.
|
||||
* Plugin of quartz-scheduler-2.x in the optional plugin folder. The reason for being an optional plugin is, many task scheduling systems are based on quartz-scheduler, this will cause duplicate tracing and link different sub-tasks as they share the same quartz level trigger, such as ElasticJob.
|
||||
|
|
|
|||
|
|
@ -172,3 +172,5 @@
|
|||
- jetty-server-11.x
|
||||
- jetty-client-11.x
|
||||
- websphere-liberty-23.x
|
||||
- spring-cloud-gateway-4.x
|
||||
- spring-webflux-6.x
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ metrics based on the tracing data.
|
|||
* Resin 3 (Optional¹)
|
||||
* Resin 4 (Optional¹)
|
||||
* [Jetty Server](http://www.eclipse.org/jetty/) 9.x -> 11.x
|
||||
* [Spring WebFlux](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html) 5.x (Optional¹)
|
||||
* [Spring WebFlux](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html) 5.x (Optional¹) -> 6.x (Optional¹)
|
||||
* [Undertow](http://undertow.io/) 1.3.0.Final -> 2.0.27.Final
|
||||
* [RESTEasy](https://resteasy.github.io/) 3.1.0.Final -> 6.2.4.Final
|
||||
* [Play Framework](https://www.playframework.com/) 2.6.x -> 2.8.x
|
||||
|
|
@ -40,7 +40,7 @@ metrics based on the tracing data.
|
|||
* [Hutool-http](https://www.hutool.cn/) client 5.x
|
||||
* [Micronaut HTTP Client](https://github.com/micronaut-projects/micronaut-core) 3.2.x -> 3.6.x
|
||||
* HTTP Gateway
|
||||
* [Spring Cloud Gateway](https://spring.io/projects/spring-cloud-gateway) 2.0.2.RELEASE -> 3.x (Optional²)
|
||||
* [Spring Cloud Gateway](https://spring.io/projects/spring-cloud-gateway) 2.0.2.RELEASE -> 4.1.x (Optional²)
|
||||
* [Apache ShenYu](https://shenyu.apache.org) (Rich protocol support: `HTTP`,`Spring Cloud`,`gRPC`,`Dubbo`,`SOFARPC`,`Motan`,`Tars`) 2.4.x (Optional²)
|
||||
* JDBC
|
||||
* Mysql Driver 5.x, 6.x, 8.x
|
||||
|
|
|
|||
|
|
@ -0,0 +1,155 @@
|
|||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
segmentItems:
|
||||
- serviceName: gateway-projectB-scenario
|
||||
segmentSize: nq 0
|
||||
segments:
|
||||
- segmentId: not null
|
||||
spans:
|
||||
- operationName: /provider/timeout/error
|
||||
parentSpanId: 0
|
||||
spanId: 1
|
||||
isError: true
|
||||
spanType: Exit
|
||||
tags:
|
||||
- { key: url, value: not null }
|
||||
- { key: http.method, value: GET }
|
||||
- { key: http.status_code, value: '500' }
|
||||
logs:
|
||||
- logEvent:
|
||||
- { key: event, value: error }
|
||||
- { key: error.kind, value: not null }
|
||||
- { key: message, value: not null }
|
||||
- {key: stack, value: not null}
|
||||
- logEvent:
|
||||
- { key: event, value: error }
|
||||
- { key: error.kind, value: not null }
|
||||
- { key: message, value: not null }
|
||||
- { key: stack, value: not null }
|
||||
- operationName: GET:/provider/b/testcase
|
||||
parentSpanId: -1
|
||||
spanId: 0
|
||||
spanLayer: Http
|
||||
startTime: nq 0
|
||||
endTime: nq 0
|
||||
componentId: 14
|
||||
isError: false
|
||||
spanType: Entry
|
||||
peer: ''
|
||||
tags:
|
||||
- {key: url, value: not null}
|
||||
- {key: http.method, value: GET}
|
||||
- {key: http.status_code, value: '200'}
|
||||
refs:
|
||||
- {parentEndpoint: SpringCloudGateway/RoutingFilter, networkAddress: 'localhost:18070',
|
||||
refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not
|
||||
null, parentService: not null, traceId: not null}
|
||||
skipAnalysis: 'false'
|
||||
- serviceName: gateway-projectA-scenario
|
||||
segmentSize: nq 0
|
||||
segments:
|
||||
- segmentId: not null
|
||||
spans:
|
||||
- operationName: /provider/timeout/error
|
||||
parentSpanId: -1
|
||||
spanId: 0
|
||||
spanLayer: Http
|
||||
isError: true
|
||||
spanType: Entry
|
||||
tags:
|
||||
- {key: url, value: 'http://localhost:8080/provider/timeout/error' }
|
||||
- {key: http.method, value: GET}
|
||||
- {key: http.status_code, value: '500'}
|
||||
- segmentId: not null
|
||||
spans:
|
||||
- operationName: SpringCloudGateway/sendRequest
|
||||
parentSpanId: 0
|
||||
spanId: 1
|
||||
spanLayer: Http
|
||||
startTime: nq 0
|
||||
endTime: nq 0
|
||||
componentId: 61
|
||||
isError: true
|
||||
spanType: Exit
|
||||
peer: 1.2.3.4:18070
|
||||
skipAnalysis: false
|
||||
tags:
|
||||
- { key: url, value: not null }
|
||||
logs:
|
||||
- logEvent:
|
||||
- { key: event, value: error }
|
||||
- { key: error.kind, value: not null }
|
||||
- { key: message, value: not null }
|
||||
- { key: stack, value: not null}
|
||||
- operationName: SpringCloudGateway/RoutingFilter
|
||||
parentSpanId: -1
|
||||
spanId: 0
|
||||
startTime: nq 0
|
||||
endTime: nq 0
|
||||
componentId: 61
|
||||
spanType: Local
|
||||
refs:
|
||||
- { parentEndpoint: '/provider/timeout/error', networkAddress: '', refType: CrossThread,
|
||||
parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not
|
||||
null, parentService: not null, traceId: not null }
|
||||
skipAnalysis: 'false'
|
||||
- segmentId: not null
|
||||
spans:
|
||||
- operationName: SpringCloudGateway/sendRequest
|
||||
parentSpanId: 0
|
||||
spanId: 1
|
||||
spanLayer: Http
|
||||
startTime: nq 0
|
||||
endTime: nq 0
|
||||
componentId: 61
|
||||
isError: false
|
||||
spanType: Exit
|
||||
peer: 'localhost:18070'
|
||||
tags:
|
||||
- {key: url, value: not null}
|
||||
- {key: http.status_code, value: '200'}
|
||||
skipAnalysis: 'false'
|
||||
- operationName: SpringCloudGateway/RoutingFilter
|
||||
parentSpanId: -1
|
||||
spanId: 0
|
||||
startTime: nq 0
|
||||
endTime: nq 0
|
||||
componentId: 61
|
||||
isError: false
|
||||
spanType: Local
|
||||
peer: ''
|
||||
refs:
|
||||
- {parentEndpoint: '/provider/b/testcase', networkAddress: '', refType: CrossThread,
|
||||
parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not
|
||||
null, parentService: not null, traceId: not null}
|
||||
skipAnalysis: 'false'
|
||||
- segmentId: not null
|
||||
spans:
|
||||
- operationName: /provider/b/testcase
|
||||
parentSpanId: -1
|
||||
spanId: 0
|
||||
spanLayer: Http
|
||||
startTime: nq 0
|
||||
endTime: nq 0
|
||||
componentId: 67
|
||||
isError: false
|
||||
spanType: Entry
|
||||
peer: not null
|
||||
tags:
|
||||
- { key: url, value: 'http://localhost:8080/provider/b/testcase' }
|
||||
- { key: http.method, value: GET }
|
||||
- { key: http.status_code, value: '200' }
|
||||
skipAnalysis: 'false'
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
type: jvm
|
||||
entryService: http://localhost:8080/provider/b/testcase
|
||||
healthCheck: http://localhost:8080/provider/b/healthCheck
|
||||
startScript: ./bin/startup.sh
|
||||
runningMode: with_optional
|
||||
withPlugins: apm-spring-cloud-gateway-4.x-plugin-*.jar
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
home="$(cd "$(dirname $0)"; pwd)"
|
||||
|
||||
java -jar ${agent_opts} "-Dskywalking.agent.service_name=gateway-projectA-scenario" ${home}/../libs/gateway-projectA-scenario.jar &
|
||||
sleep 1
|
||||
|
||||
java -jar ${agent_opts} "-Dskywalking.agent.service_name=gateway-projectB-scenario" ${home}/../libs/gateway-projectB-scenario.jar &
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.apache.skywalking</groupId>
|
||||
<artifactId>gateway-4.x-scenario</artifactId>
|
||||
<version>5.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>gateway-dist</artifactId>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assemble</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
<outputDirectory>../target/</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>./bin</directory>
|
||||
<fileMode>0775</fileMode>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
|
||||
<files>
|
||||
<file>
|
||||
<source>../gateway-projectA-scenario/target/gateway-projectA-scenario.jar</source>
|
||||
<outputDirectory>./libs</outputDirectory>
|
||||
<fileMode>0775</fileMode>
|
||||
</file>
|
||||
<file>
|
||||
<source>../gateway-projectB-scenario/target/gateway-projectB-scenario.jar</source>
|
||||
<outputDirectory>./libs</outputDirectory>
|
||||
<fileMode>0775</fileMode>
|
||||
</file>
|
||||
</files>
|
||||
</assembly>
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.apache.skywalking</groupId>
|
||||
<artifactId>gateway-4.x-scenario</artifactId>
|
||||
<version>5.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>gateway-projectA-scenario</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
<version>${test.framework.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>gateway-projectA-scenario</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package test.apache.skywalking.apm.testcase.sc.gateway.projectA;
|
||||
|
||||
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Component
|
||||
public class ApiKeyResolver implements KeyResolver {
|
||||
|
||||
public Mono<String> resolve(ServerWebExchange exchange) {
|
||||
return Mono.just(exchange.getRequest().getPath().value());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package test.apache.skywalking.apm.testcase.sc.gateway.projectA;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package test.apache.skywalking.apm.testcase.sc.gateway.projectA;
|
||||
|
||||
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.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class Test1Filter implements GlobalFilter, Ordered {
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
ServerHttpRequest buildRequest = exchange.getRequest().mutate().build();
|
||||
return chain.filter(exchange.mutate().request(buildRequest).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package test.apache.skywalking.apm.testcase.sc.gateway.projectA;
|
||||
|
||||
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.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class Test2Filter implements GlobalFilter, Ordered {
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
ServerHttpRequest buildRequest = exchange.getRequest().mutate().build();
|
||||
return chain.filter(exchange.mutate().request(buildRequest).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package test.apache.skywalking.apm.testcase.sc.gateway.projectA;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class TestFilterConfig {
|
||||
|
||||
@Bean
|
||||
public Test1Filter test1Filter() {
|
||||
return new Test1Filter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Test2Filter test2Filter() {
|
||||
return new Test2Filter();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
spring:
|
||||
cloud:
|
||||
gateway:
|
||||
httpclient:
|
||||
connect-timeout: 2000
|
||||
routes:
|
||||
- id: provider_route
|
||||
uri: http://localhost:18070
|
||||
predicates:
|
||||
- Path=/provider/b/*
|
||||
- id: provider_timeout
|
||||
uri: http://1.2.3.4:18070
|
||||
predicates:
|
||||
- Path=/provider/timeout/*
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>gateway-4.x-scenario</artifactId>
|
||||
<groupId>org.apache.skywalking</groupId>
|
||||
<version>5.0.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>gateway-projectB-scenario</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>2.1.0.RELEASE</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>gateway-projectB-scenario</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>1.5.9.RELEASE</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package test.apache.skywalking.apm.testcase.sc.gateway.projectB;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@SpringBootApplication
|
||||
@ComponentScan(value = {"test.apache.skywalking.apm.testcase.sc.gateway.projectB.controller"})
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package test.apache.skywalking.apm.testcase.sc.gateway.projectB.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@RestController
|
||||
public class TestController {
|
||||
|
||||
@RequestMapping("/provider/b/testcase")
|
||||
public String testcase() {
|
||||
try {
|
||||
new RestTemplate().getForEntity("http://localhost:8080/provider/timeout/error", String.class);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return "1";
|
||||
}
|
||||
|
||||
@RequestMapping("/provider/b/healthCheck")
|
||||
public String healthCheck() {
|
||||
return "Success";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
server.port=18070
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
~ contributor license agreements. See the NOTICE file distributed with
|
||||
~ this work for additional information regarding copyright ownership.
|
||||
~ The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
~ (the "License"); you may not use this file except in compliance with
|
||||
~ the License. You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
~
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.apache.skywalking</groupId>
|
||||
<artifactId>gateway-4.x-scenario</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>5.0.0</version>
|
||||
<modules>
|
||||
<module>gateway-projectA-scenario</module>
|
||||
<module>gateway-projectB-scenario</module>
|
||||
<module>gateway-dist</module>
|
||||
</modules>
|
||||
|
||||
<name>skywalking-gateway-4.x-scenario</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<compiler.version>1.8</compiler.version>
|
||||
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
|
||||
<test.framework.version>4.0.0</test.framework.version>
|
||||
<docker.image.version>${test.framework.version}</docker.image.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<finalName>gateway-4.x-scenario</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${compiler.version}</source>
|
||||
<target>${compiler.version}</target>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
4.0.0
|
||||
4.0.8
|
||||
4.1.0
|
||||
Loading…
Reference in New Issue