[Feature] Support for tracking in spring gateway versions 4.1.2 and above (#747)

This commit is contained in:
yqw570994511 2025-01-11 18:09:42 +08:00 committed by GitHub
parent 31bf638213
commit 35495375d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
53 changed files with 3543 additions and 5 deletions

View File

@ -53,6 +53,9 @@ jobs:
- os: ubuntu
java-version: 21
steps:
- if: matrix.os == 'windows'
name: Support longpaths
run: git config --system core.longpaths true
- uses: actions/checkout@v2
with:
submodules: true

View File

@ -58,6 +58,7 @@ jobs:
- spring-6.x-scenario
- resteasy-6.x-scenario
- gateway-4.x-scenario
- gateway-4.1.2.x-scenario
- httpexchange-scenario
- activemq-artemis-2.x-scenario
- c3p0-0.9.0.x-0.9.1.x-scenario

View File

@ -27,6 +27,7 @@ Release Notes.
field as new propagation mechanism, to better support async scenarios.
* Add Caffeine plugin as optional.
* Add Undertow 2.1.7.final+ worker thread pool metrics.
* Support for tracking in spring gateway versions 4.1.2 and above.
All issues and pull requests are [here](https://github.com/apache/skywalking/milestone/222?closed=1)

View File

@ -56,7 +56,7 @@ public class GatewayFilterInstrumentation extends AbstractGateway200EnhancePlugi
@Override
public boolean isOverrideArgs() {
return true;
return false;
}
}
};

View File

@ -56,7 +56,7 @@ public class GatewayFilterInstrumentation extends AbstractGateway210EnhancePlugi
@Override
public boolean isOverrideArgs() {
return true;
return false;
}
}
};

View File

@ -59,7 +59,7 @@ public class GatewayFilterInstrumentation extends AbstractGatewayV3EnhancePlugin
@Override
public boolean isOverrideArgs() {
return true;
return false;
}
}
};

View File

@ -0,0 +1,94 @@
/*
* 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.v412x;
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 org.springframework.web.server.adapter.DefaultServerWebExchange;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicInteger;
import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.SPRING_CLOUD_GATEWAY;
public class GatewayFilterV412Interceptor implements InstanceMethodsAroundInterceptor {
private static final ThreadLocal<AtomicInteger> STACK_DEEP = ThreadLocal.withInitial(() -> new AtomicInteger(0));
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
if (isEntry()) {
ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
EnhancedInstance enhancedInstance = getInstance(exchange);
AbstractSpan span = ContextManager.createLocalSpan("SpringCloudGateway/GatewayFilter");
if (enhancedInstance != null && enhancedInstance.getSkyWalkingDynamicField() != null) {
ContextManager.continued((ContextSnapshot) enhancedInstance.getSkyWalkingDynamicField());
}
span.setComponent(SPRING_CLOUD_GATEWAY);
}
}
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;
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
if (isExit()) {
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
}
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
ContextManager.activeSpan().log(t);
}
private boolean isEntry() {
return STACK_DEEP.get().getAndIncrement() == 0;
}
private boolean isExit() {
boolean isExit = STACK_DEEP.get().decrementAndGet() == 0;
if (isExit) {
STACK_DEEP.remove();
}
return isExit;
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.v412x;
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;
public class HttpClientConnectDuplicateV412Interceptor 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 (objInst.getSkyWalkingDynamicField() != null) {
EnhanceObjectCache enhanceObjectCache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
if (ret instanceof EnhancedInstance) {
EnhancedInstance retEnhancedInstance = (EnhancedInstance) ret;
retEnhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
}
}
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
}
}

View File

@ -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.v412x;
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;
public class HttpClientConnectRequestV412Interceptor 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 (objInst.getSkyWalkingDynamicField() != null) {
if (ret instanceof EnhancedInstance) {
EnhancedInstance retEnhancedInstance = (EnhancedInstance) ret;
Object retSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
if (retSkyWalkingDynamicField != null) {
EnhanceObjectCache retEnhanceObjectCache = (EnhanceObjectCache) retSkyWalkingDynamicField;
EnhanceObjectCache objEnhanceObjectCache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
retEnhanceObjectCache.setContextSnapshot(objEnhanceObjectCache.getContextSnapshot());
}
}
}
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
}
}

View File

@ -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.v412x;
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 HttpClientConfig} class instance which can get the
* request uri string.
*/
public class HttpClientFinalizerConstructorV412Interceptor 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);
}
}

View File

@ -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.v412x;
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 HttpClientFinalizerResponseConnectionV412Interceptor 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) {
}
}

View File

@ -0,0 +1,112 @@
/*
* 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.v412x;
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.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 HttpClientFinalizerSendV412Interceptor 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;
}
ContextSnapshot contextSnapshot = enhanceObjectCache.getContextSnapshot();
if (contextSnapshot == null) {
return;
}
AbstractSpan span = ContextManager.createLocalSpan("SpringCloudGateway/send");
ContextManager.continued(contextSnapshot);
span.setComponent(SPRING_CLOUD_GATEWAY);
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) {
}
}

View File

@ -0,0 +1,57 @@
/*
* 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.v412x;
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 HttpClientFinalizerUriV412Interceptor 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 retEnhanceObjectCache = (EnhanceObjectCache) ((EnhancedInstance) ret).getSkyWalkingDynamicField();
if (retEnhanceObjectCache != null) {
retEnhanceObjectCache.setUrl(String.valueOf(allArguments[0]));
if (objInst.getSkyWalkingDynamicField() != null) {
EnhanceObjectCache objInstEnhanceObjectCache = (EnhanceObjectCache) objInst.getSkyWalkingDynamicField();
retEnhanceObjectCache.setContextSnapshot(objInstEnhanceObjectCache.getContextSnapshot());
}
}
}
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
}
}

View File

@ -0,0 +1,91 @@
/*
* 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.v412x;
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;
public class NettyRoutingFilterV412Interceptor implements InstanceMethodsAroundInterceptor {
private static final String NETTY_ROUTING_FILTER_TRACED_ATTR = NettyRoutingFilterV412Interceptor.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 {
if (ContextManager.isActive()) {
// if HttpClientFinalizerSendInterceptor does not invoke, we will stop the span there to avoid context leak.
ContextManager.stopSpan();
}
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
ContextManager.activeSpan().log(t);
}
}

View File

@ -0,0 +1,55 @@
/*
* 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.v412x;
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.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;
public class NettyRoutingGetHttpClientV412Interceptor 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) {
if (ContextManager.isActive()) {
ContextSnapshot contextSnapshot = ContextManager.capture();
EnhanceObjectCache retEnhanceObjectCache = new EnhanceObjectCache();
retEnhanceObjectCache.setContextSnapshot(contextSnapshot);
EnhancedInstance retEnhancedInstance = (EnhancedInstance) ret;
retEnhancedInstance.setSkyWalkingDynamicField(retEnhanceObjectCache);
}
}
return ret;
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
}
}

View File

@ -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.v412x.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 AbstractGatewayV412EnhancePluginDefine extends ClassInstanceMethodsEnhancePluginDefine {
/**
* @since 4.0.0
*/
@Override
protected String[] witnessClasses() {
return new String[]{"org.springframework.cloud.gateway.event.RouteDeletedEvent"};
}
}

View File

@ -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.v412x.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 org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
public class GatewayFilterV412Instrumentation extends AbstractGatewayV412EnhancePluginDefine {
private static final String INTERCEPT_CLASS_GATEWAY_FILTER = "org.springframework.cloud.gateway.filter.GatewayFilter";
private static final String GATEWAY_FILTER_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.GatewayFilterV412Interceptor";
@Override
protected ClassMatch enhanceClass() {
return HierarchyMatch.byHierarchyMatch(INTERCEPT_CLASS_GATEWAY_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 GATEWAY_FILTER_INTERCEPTOR;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

View File

@ -0,0 +1,87 @@
/*
* 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.v412x.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 net.bytebuddy.matcher.ElementMatchers.returns;
import static net.bytebuddy.matcher.ElementMatchers.takesNoArguments;
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
public class HttpClientConnectV412Instrumentation extends AbstractGatewayV412EnhancePluginDefine {
private static final String ENHANCE_CLASS = "reactor.netty.http.client.HttpClientConnect";
private static final String HTTP_CLIENT_CONNECT_DUPLICATE_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.HttpClientConnectDuplicateV412Interceptor";
private static final String HTTP_CLIENT_CONNECT_REQUEST_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.HttpClientConnectRequestV412Interceptor";
@Override
protected ClassMatch enhanceClass() {
return byName(ENHANCE_CLASS);
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[0];
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("duplicate").and(takesNoArguments())
.and(returns(named("reactor.netty.http.client.HttpClient")));
}
@Override
public String getMethodsInterceptor() {
return HTTP_CLIENT_CONNECT_DUPLICATE_INTERCEPTOR;
}
@Override
public boolean isOverrideArgs() {
return false;
}
},
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("request").and(takesArgumentWithType(0, "io.netty.handler.codec.http.HttpMethod"))
.and(returns(named("reactor.netty.http.client.HttpClient$RequestSender")));
}
@Override
public String getMethodsInterceptor() {
return HTTP_CLIENT_CONNECT_REQUEST_INTERCEPTOR;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

View File

@ -0,0 +1,114 @@
/*
* 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.v412x.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;
public class HttpClientFinalizerV412Instrumentation extends AbstractGatewayV412EnhancePluginDefine {
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.v412x.HttpClientFinalizerConstructorV412Interceptor";
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.v412x.HttpClientFinalizerUriV412Interceptor";
private static final String HTTP_CLIENT_FINALIZER_SEND_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.HttpClientFinalizerSendV412Interceptor";
private static final String HTTP_CLIENT_FINALIZER_RESPONSE_CONNECTION_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.HttpClientFinalizerResponseConnectionV412Interceptor";
@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;
}
}
};
}
}

View File

@ -0,0 +1,89 @@
/*
* 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.v412x.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 net.bytebuddy.matcher.ElementMatchers.returns;
import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
public class NettyRoutingFilterV412Instrumentation extends AbstractGatewayV412EnhancePluginDefine {
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.v412x.NettyRoutingFilterV412Interceptor";
private static final String NETTY_ROUTING_GET_HTTP_CLIENT_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.NettyRoutingGetHttpClientV412Interceptor";
@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;
}
},
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("getHttpClient")
.and(takesArgumentWithType(0, "org.springframework.cloud.gateway.route.Route"))
.and(takesArgumentWithType(1, "org.springframework.web.server.ServerWebExchange"))
.and(returns(named("reactor.netty.http.client.HttpClient")));
}
@Override
public String getMethodsInterceptor() {
return NETTY_ROUTING_GET_HTTP_CLIENT_INTERCEPTOR;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

View File

@ -17,8 +17,15 @@
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define;
import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import java.util.Collections;
import java.util.List;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.returns;
/**
* This abstract class defines the <code>witnessClasses()</code> method,
* and other plugin define classes need to inherit from this class
@ -32,4 +39,12 @@ public abstract class AbstractGatewayV4EnhancePluginDefine extends ClassInstance
protected String[] witnessClasses() {
return new String[]{"org.springframework.cloud.gateway.filter.factory.cache.LocalResponseCacheProperties"};
}
@Override
protected List<WitnessMethod> witnessMethods() {
return Collections.singletonList(
new WitnessMethod("org.springframework.cloud.gateway.config.LocalResponseCacheAutoConfiguration",
named("responseCacheSizeWeigher").
and(returns(named("org.springframework.cloud.gateway.filter.factory.cache.ResponseCacheSizeWeigher")))));
}
}

View File

@ -17,6 +17,7 @@
package org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define;
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
/**
@ -27,6 +28,7 @@ public class EnhanceObjectCache {
private String url;
private AbstractSpan span;
private AbstractSpan span1;
private ContextSnapshot contextSnapshot;
public String getUrl() {
return url;
@ -51,4 +53,13 @@ public class EnhanceObjectCache {
public void setSpan1(final AbstractSpan span) {
span1 = span;
}
public ContextSnapshot getContextSnapshot() {
return contextSnapshot;
}
public void setContextSnapshot(final ContextSnapshot contextSnapshot) {
this.contextSnapshot = contextSnapshot;
}
}

View File

@ -59,7 +59,7 @@ public class GatewayFilterInstrumentation extends AbstractGatewayV4EnhancePlugin
@Override
public boolean isOverrideArgs() {
return true;
return false;
}
}
};

View File

@ -19,3 +19,7 @@ spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v
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
spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v4x.define.GatewayFilterInstrumentation
spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.define.HttpClientFinalizerV412Instrumentation
spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.define.NettyRoutingFilterV412Instrumentation
spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.define.GatewayFilterV412Instrumentation
spring-cloud-gateway-4.x=org.apache.skywalking.apm.plugin.spring.cloud.gateway.v412x.define.HttpClientConnectV412Instrumentation

View File

@ -0,0 +1,332 @@
/*
* 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.v412x;
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;
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;
@RunWith(TracingSegmentRunner.class)
public class GatewayFilterV412InterceptorTest {
private static final String GATEWAY_FILTER_INTERCEPTOR_LOCAL_SPAN_OPERATION_NAME = "SpringCloudGateway/GatewayFilter";
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 GatewayFilterV412Interceptor interceptor = new GatewayFilterV412Interceptor();
@Rule
public AgentServiceRule serviceRule = new AgentServiceRule();
@Rule
public MockitoRule rule = MockitoJUnit.rule();
@SegmentStoragePoint
private SegmentStorage segmentStorage;
@Before
public void setUp() throws Exception {
}
private final ServerWebExchange exchange = new ServerWebExchange() {
Map<String, Object> attributes = new HashMap<>();
@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;
}
};
@Test
public void testInterceptOnlyOnce() throws Throwable {
interceptor.beforeMethod(null, null, new Object[]{exchange}, null, null);
Assert.assertTrue(ContextManager.isActive());
AbstractSpan activeSpan = ContextManager.activeSpan();
Assert.assertTrue(activeSpan instanceof AbstractTracingSpan);
Assert.assertEquals(activeSpan.getOperationName(), GATEWAY_FILTER_INTERCEPTOR_LOCAL_SPAN_OPERATION_NAME);
interceptor.afterMethod(null, null, null, null, null);
Assert.assertFalse(ContextManager.isActive());
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 testNestedInterception() throws Throwable {
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
Assert.assertTrue(ContextManager.isActive());
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
Assert.assertTrue(ContextManager.isActive());
interceptor.afterMethod(null, null, null, null, null);
Assert.assertTrue(ContextManager.isActive());
interceptor.afterMethod(null, null, null, null, null);
Assert.assertFalse(ContextManager.isActive());
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 testWithNullDynamicField() throws Throwable {
interceptor.beforeMethod(null, null, new Object[]{enhancedInstance}, null, null);
interceptor.afterMethod(null, null, null, null, null);
// no more need this, span was stopped at interceptor#afterMethod
// 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);
// no more need this, span was stopped at interceptor#afterMethod
// 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);
}
}

View File

@ -0,0 +1,125 @@
/*
* 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.v412x;
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.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.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.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 java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@RunWith(TracingSegmentRunner.class)
public class HttpClientConnectDuplicateV412InterceptorTest {
private final static String ENTRY_OPERATION_NAME = "/get";
private final HttpClientConnectDuplicateV412Interceptor duplicateInterceptor = new HttpClientConnectDuplicateV412Interceptor();
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 final EnhancedInstance retEnhancedInstance = 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();
@SegmentStoragePoint
private SegmentStorage segmentStorage;
private AbstractSpan entrySpan;
@Before
public void setUp() throws Exception {
entrySpan = ContextManager.createEntrySpan(ENTRY_OPERATION_NAME, null);
entrySpan.setLayer(SpanLayer.HTTP);
entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
}
@Test
public void testWithDynamicFieldNull() throws Throwable {
enhancedInstance.setSkyWalkingDynamicField(null);
duplicateInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
assertNull(retEnhancedInstance.getSkyWalkingDynamicField());
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(traceSegments.size(), 0);
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
}
@Test
public void testWithDynamicFieldNotNull() throws Throwable {
ContextSnapshot contextSnapshot = ContextManager.capture();
EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
enhanceObjectCache.setContextSnapshot(contextSnapshot);
enhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
duplicateInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
Object retEnhancedInstanceSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
assertNotNull(retEnhancedInstanceSkyWalkingDynamicField);
assertTrue(retEnhancedInstanceSkyWalkingDynamicField instanceof EnhanceObjectCache);
EnhanceObjectCache retEnhanceObjectCache = (EnhanceObjectCache) retEnhancedInstanceSkyWalkingDynamicField;
assertNotNull(retEnhanceObjectCache.getContextSnapshot());
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(traceSegments.size(), 0);
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
}
}

View File

@ -0,0 +1,165 @@
/*
* 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.v412x;
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.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.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.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 java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@RunWith(TracingSegmentRunner.class)
public class HttpClientConnectRequestV412InterceptorTest {
private final static String URI = "http://localhost:8080/get";
private final static String ENTRY_OPERATION_NAME = "/get";
private final HttpClientConnectRequestV412Interceptor requestInterceptor = new HttpClientConnectRequestV412Interceptor();
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 final EnhancedInstance retEnhancedInstance = 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();
@SegmentStoragePoint
private SegmentStorage segmentStorage;
private AbstractSpan entrySpan;
@Before
public void setUp() throws Exception {
entrySpan = ContextManager.createEntrySpan(ENTRY_OPERATION_NAME, null);
entrySpan.setLayer(SpanLayer.HTTP);
entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
}
@Test
public void testWithDynamicFieldNull() throws Throwable {
enhancedInstance.setSkyWalkingDynamicField(null);
retEnhancedInstance.setSkyWalkingDynamicField(null);
requestInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
assertNull(retEnhancedInstance.getSkyWalkingDynamicField());
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(traceSegments.size(), 0);
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
}
@Test
public void testWithRetDynamicFieldNotNull() throws Throwable {
enhancedInstance.setSkyWalkingDynamicField(null);
EnhanceObjectCache retEnhanceObjectCache = new EnhanceObjectCache();
retEnhancedInstance.setSkyWalkingDynamicField(retEnhanceObjectCache);
requestInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
assertNotNull(retEnhancedInstance.getSkyWalkingDynamicField());
assertTrue(retEnhancedInstance.getSkyWalkingDynamicField() instanceof EnhanceObjectCache);
assertNull(((EnhanceObjectCache) retEnhancedInstance.getSkyWalkingDynamicField()).getContextSnapshot());
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(traceSegments.size(), 0);
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
}
@Test
public void testWithDynamicFieldNotNull() throws Throwable {
ContextSnapshot contextSnapshot = ContextManager.capture();
EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
enhanceObjectCache.setContextSnapshot(contextSnapshot);
enhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
EnhanceObjectCache enhanceObjectCache2 = new EnhanceObjectCache();
enhanceObjectCache2.setUrl(URI);
retEnhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache2);
requestInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
Object retEnhancedInstanceSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
assertNotNull(retEnhancedInstanceSkyWalkingDynamicField);
assertTrue(retEnhancedInstanceSkyWalkingDynamicField instanceof EnhanceObjectCache);
EnhanceObjectCache retEnhanceObjectCache = (EnhanceObjectCache) retEnhancedInstanceSkyWalkingDynamicField;
assertNotNull(retEnhanceObjectCache.getContextSnapshot());
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(traceSegments.size(), 0);
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
}
@Test
public void testWithRetDynamicFieldNull() throws Throwable {
ContextSnapshot contextSnapshot = ContextManager.capture();
EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
enhanceObjectCache.setContextSnapshot(contextSnapshot);
enhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
retEnhancedInstance.setSkyWalkingDynamicField(null);
requestInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
Object retEnhancedInstanceSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
assertNull(retEnhancedInstanceSkyWalkingDynamicField);
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(traceSegments.size(), 0);
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.v412x;
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;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class HttpClientFinalizerConstructorV412InterceptorTest {
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 HttpClientFinalizerConstructorV412Interceptor httpClientFinalizerConstructorInterceptor;
@Before
public void setUp() {
httpClientConfig = mock(HttpClientConfig.class);
when(httpClientConfig.uri()).thenReturn(URI);
httpClientFinalizerConstructorInterceptor = new HttpClientFinalizerConstructorV412Interceptor();
}
@Test
public void onConstruct() {
httpClientFinalizerConstructorInterceptor.onConstruct(enhancedInstance, new Object[]{httpClientConfig});
final EnhanceObjectCache enhanceCache = (EnhanceObjectCache) enhancedInstance.getSkyWalkingDynamicField();
assertNotNull(enhanceCache);
assertEquals(enhanceCache.getUrl(), URI);
}
}

View File

@ -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.v412x;
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.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.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.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 java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@RunWith(TracingSegmentRunner.class)
public class HttpClientFinalizerUriV412InterceptorTest {
private final static String URI = "http://localhost:8080/get";
private final static String ENTRY_OPERATION_NAME = "/get";
private final HttpClientFinalizerUriV412Interceptor uriInterceptor = new HttpClientFinalizerUriV412Interceptor();
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 final EnhancedInstance retEnhancedInstance = 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();
@SegmentStoragePoint
private SegmentStorage segmentStorage;
private AbstractSpan entrySpan;
@Before
public void setUp() throws Exception {
entrySpan = ContextManager.createEntrySpan(ENTRY_OPERATION_NAME, null);
entrySpan.setLayer(SpanLayer.HTTP);
entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
}
@Test
public void testWithDynamicFieldNull() throws Throwable {
enhancedInstance.setSkyWalkingDynamicField(null);
retEnhancedInstance.setSkyWalkingDynamicField(null);
uriInterceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
assertNull(retEnhancedInstance.getSkyWalkingDynamicField());
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(traceSegments.size(), 0);
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
}
@Test
public void testWithRetDynamicFieldNotNull() throws Throwable {
enhancedInstance.setSkyWalkingDynamicField(null);
EnhanceObjectCache enhanceObjectCache2 = new EnhanceObjectCache();
retEnhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache2);
uriInterceptor.afterMethod(enhancedInstance, null, new Object[]{URI}, null, retEnhancedInstance);
Object retEnhancedInstanceSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
assertNotNull(retEnhancedInstanceSkyWalkingDynamicField);
assertTrue(retEnhancedInstanceSkyWalkingDynamicField instanceof EnhanceObjectCache);
EnhanceObjectCache retEnhanceObjectCache = (EnhanceObjectCache) retEnhancedInstanceSkyWalkingDynamicField;
assertNull(retEnhanceObjectCache.getContextSnapshot());
assertNotNull(retEnhanceObjectCache.getUrl());
assertEquals(URI, retEnhanceObjectCache.getUrl());
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(traceSegments.size(), 0);
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
}
@Test
public void testWithDynamicFieldNotNull() throws Throwable {
ContextSnapshot contextSnapshot = ContextManager.capture();
EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
enhanceObjectCache.setContextSnapshot(contextSnapshot);
enhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
EnhanceObjectCache enhanceObjectCache2 = new EnhanceObjectCache();
retEnhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache2);
uriInterceptor.afterMethod(enhancedInstance, null, new Object[]{URI}, null, retEnhancedInstance);
Object retEnhancedInstanceSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
assertNotNull(retEnhancedInstanceSkyWalkingDynamicField);
assertTrue(retEnhancedInstanceSkyWalkingDynamicField instanceof EnhanceObjectCache);
EnhanceObjectCache retEnhanceObjectCache = (EnhanceObjectCache) retEnhancedInstanceSkyWalkingDynamicField;
assertNotNull(retEnhanceObjectCache.getContextSnapshot());
assertTrue(contextSnapshot == retEnhanceObjectCache.getContextSnapshot());
assertNotNull(retEnhanceObjectCache.getUrl());
assertEquals(URI, retEnhanceObjectCache.getUrl());
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(traceSegments.size(), 0);
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
}
@Test
public void testWithRetDynamicFieldNull() throws Throwable {
ContextSnapshot contextSnapshot = ContextManager.capture();
EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
enhanceObjectCache.setContextSnapshot(contextSnapshot);
enhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
retEnhancedInstance.setSkyWalkingDynamicField(null);
uriInterceptor.afterMethod(enhancedInstance, null, new Object[]{URI}, null, retEnhancedInstance);
Object retEnhancedInstanceSkyWalkingDynamicField = retEnhancedInstance.getSkyWalkingDynamicField();
assertNull(retEnhancedInstanceSkyWalkingDynamicField);
assertNotNull(enhancedInstance.getSkyWalkingDynamicField());
assertTrue(enhancedInstance.getSkyWalkingDynamicField() instanceof EnhanceObjectCache);
EnhanceObjectCache objInstObjectCache = (EnhanceObjectCache) enhancedInstance.getSkyWalkingDynamicField();
assertTrue(contextSnapshot == objInstObjectCache.getContextSnapshot());
assertNull(objInstObjectCache.getUrl());
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(traceSegments.size(), 0);
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
}
}

View File

@ -0,0 +1,204 @@
/*
* 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.v412x;
import io.netty.handler.codec.http.HttpResponseStatus;
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 reactor.core.publisher.Flux;
import reactor.netty.Connection;
import reactor.netty.NettyOutbound;
import reactor.netty.http.client.HttpClientRequest;
import reactor.netty.http.client.HttpClientResponse;
import java.util.List;
import java.util.function.BiFunction;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@RunWith(TracingSegmentRunner.class)
public class HttpClientFinalizerV412InterceptorTest {
private final static String URI = "http://localhost:8080/get";
private final static String ENTRY_OPERATION_NAME = "/get";
private final HttpClientFinalizerSendV412Interceptor sendInterceptor = new HttpClientFinalizerSendV412Interceptor();
private final HttpClientFinalizerResponseConnectionV412Interceptor responseConnectionInterceptor = new HttpClientFinalizerResponseConnectionV412Interceptor();
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 {
entrySpan = ContextManager.createEntrySpan(ENTRY_OPERATION_NAME, null);
entrySpan.setLayer(SpanLayer.HTTP);
entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
mockRequest = new MockClientRequest();
mockResponse = new MockClientResponse();
final EnhanceObjectCache enhanceObjectCache = new EnhanceObjectCache();
enhanceObjectCache.setUrl(URI);
enhanceObjectCache.setContextSnapshot(ContextManager.capture());
enhancedInstance.setSkyWalkingDynamicField(enhanceObjectCache);
}
@Test
public void testWithDynamicFieldNull() throws Throwable {
enhancedInstance.setSkyWalkingDynamicField(null);
executeSendRequest();
stopEntrySpan();
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(1, traceSegments.size());
}
@Test
public void testWithContextSnapshotNull() throws Throwable {
EnhanceObjectCache objectCache = (EnhanceObjectCache) enhancedInstance.getSkyWalkingDynamicField();
objectCache.setContextSnapshot(null);
executeSendRequest();
stopEntrySpan();
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(1, traceSegments.size());
}
@Test
public void testWithEmptyUri() throws Throwable {
final EnhanceObjectCache objectCache = (EnhanceObjectCache) enhancedInstance.getSkyWalkingDynamicField();
objectCache.setUrl("");
executeSendRequest();
stopEntrySpan();
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(1, traceSegments.size());
final List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegments.get(0));
assertNotNull(spans);
assertEquals(2, spans.size());
assertNotNull(spans.get(1));
assertUpstreamSpan(spans.get(1));
assertNotNull(spans.get(0));
assertSendSpan(spans.get(0));
assertNotNull(objectCache.getSpan1());
assertEquals(objectCache.getSpan1().getSpanId(), spans.get(0).getSpanId());
}
@Test
public void testWithUri() throws Throwable {
executeSendRequest();
stopEntrySpan();
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(1, traceSegments.size());
final EnhanceObjectCache objectCache = (EnhanceObjectCache) enhancedInstance
.getSkyWalkingDynamicField();
assertNotNull(objectCache.getSpan1());
assertNotNull(objectCache.getSpan());
assertTrue(objectCache.getSpan().isExit());
assertEquals(objectCache.getSpan().getOperationName(), "SpringCloudGateway/sendRequest");
assertEquals(objectCache.getSpan1().getOperationName(), "SpringCloudGateway/send");
final List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegments.get(0));
assertNotNull(spans);
assertEquals(3, spans.size());
assertUpstreamSpan(spans.get(2));
assertSendSpan(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 assertSendSpan(AbstractSpan span) {
SpanAssert.assertComponent(span, ComponentsDefine.SPRING_CLOUD_GATEWAY);
assertEquals(span.getOperationName(), "SpringCloudGateway/send");
}
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()));
}
private void stopEntrySpan() {
if (ContextManager.isActive() && ContextManager.activeSpan() == entrySpan) {
ContextManager.stopSpan(entrySpan);
}
}
}

View File

@ -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.v412x;
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 MockClientRequest 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;
}
}

View File

@ -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.v412x;
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;
}
}

View File

@ -0,0 +1,222 @@
/*
* 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.v412x;
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;
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;
@RunWith(TracingSegmentRunner.class)
public class NettyRoutingFilterV412InterceptorTest {
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 NettyRoutingFilterV412Interceptor interceptor = new NettyRoutingFilterV412Interceptor();
@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);
// no more need this, span was stopped at interceptor#afterMethod
// 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(1, spans.size());
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);
// no more need this, span was stopped at interceptor#afterMethod
// 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 =
NettyRoutingFilterV412Interceptor.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.assertFalse(ContextManager.isActive());
// no more need this, span was stopped at interceptor#afterMethod
// 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);
}
}

View File

@ -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.v412x;
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.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.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.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 java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@RunWith(TracingSegmentRunner.class)
public class NettyRoutingGetHttpClientV412InterceptorTest {
private final static String ENTRY_OPERATION_NAME = "/get";
private final NettyRoutingGetHttpClientV412Interceptor interceptor = new NettyRoutingGetHttpClientV412Interceptor();
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 final EnhancedInstance retEnhancedInstance = 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();
@SegmentStoragePoint
private SegmentStorage segmentStorage;
private AbstractSpan entrySpan;
@Before
public void setUp() throws Exception {
}
@Test
public void testWithContextIsActive() throws Throwable {
entrySpan = ContextManager.createEntrySpan(ENTRY_OPERATION_NAME, null);
entrySpan.setLayer(SpanLayer.HTTP);
entrySpan.setComponent(ComponentsDefine.SPRING_WEBFLUX);
interceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
assertNotNull(retEnhancedInstance.getSkyWalkingDynamicField());
assertTrue(retEnhancedInstance.getSkyWalkingDynamicField() instanceof EnhanceObjectCache);
EnhanceObjectCache enhanceObjectCache = (EnhanceObjectCache) retEnhancedInstance.getSkyWalkingDynamicField();
assertNotNull(enhanceObjectCache.getContextSnapshot());
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(traceSegments.size(), 0);
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
}
@Test
public void testWithContextNotActive() throws Throwable {
interceptor.afterMethod(enhancedInstance, null, null, null, retEnhancedInstance);
assertNull(retEnhancedInstance.getSkyWalkingDynamicField());
final List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
assertEquals(traceSegments.size(), 0);
if (ContextManager.isActive()) {
ContextManager.stopSpan();
}
}
}

View File

@ -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/send, 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/send
parentSpanId: -1
spanId: 0
startTime: nq 0
endTime: nq 0
componentId: 61
spanType: Local
refs:
- { parentEndpoint: 'SpringCloudGateway/GatewayFilter', networkAddress: '', refType: CrossThread,
parentSpanId: 1, 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/send
parentSpanId: -1
spanId: 0
startTime: nq 0
endTime: nq 0
componentId: 61
isError: false
spanType: Local
peer: ''
refs:
- {parentEndpoint: 'SpringCloudGateway/GatewayFilter', networkAddress: '', refType: CrossThread,
parentSpanId: 1, 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'

View File

@ -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

View File

@ -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 &

View File

@ -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.1.2.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>

View File

@ -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>

View File

@ -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.1.2.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>

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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/*

View File

@ -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.1.2.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>

View File

@ -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);
}
}

View File

@ -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";
}
}

View File

@ -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

View File

@ -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.1.2.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.1.2.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.1.2</test.framework.version>
<docker.image.version>${test.framework.version}</docker.image.version>
</properties>
<build>
<finalName>gateway-4.1.2.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>

View File

@ -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.1.2
4.1.6
4.2.0

View File

@ -16,4 +16,5 @@
4.0.0
4.0.8
4.1.0
4.1.0
4.1.1