From c9a61701f1b40075af78fcd829d9baed9f710a23 Mon Sep 17 00:00:00 2001 From: DarknessTM Date: Sat, 8 Jul 2023 02:26:18 +0800 Subject: [PATCH] Support access the tracer context in spring gateway filter (#539) Co-authored-by: darknesstm --- .github/workflows/plugins-test.3.yaml | 1 + CHANGES.md | 1 + .../WebFluxSkyWalkingTraceContext.java | 79 ++++++++++ .../core/context/CorrelationContext.java | 4 +- ...lkingCorrelationContextGetInterceptor.java | 49 ++++++ ...lkingCorrelationContextPutInterceptor.java | 50 ++++++ ...WebFluxSkyWalkingOperatorsInterceptor.java | 15 +- ...WebFluxSkyWalkingSegmentIDInterceptor.java | 53 +++++++ .../WebFluxSkyWalkingSpanIDInterceptor.java | 53 +++++++ ...WalkingStaticMethodsAroundInterceptor.java | 50 ++++++ ...bFluxSkyWalkingTraceContextActivation.java | 142 ++++++++++++++++++ .../WebFluxSkyWalkingTraceIDInterceptor.java | 53 +++++++ .../src/main/resources/skywalking-plugin.def | 3 +- .../java-agent/Application-toolkit-webflux.md | 50 +++++- .../config/expectedData.yaml | 64 ++++++++ .../configuration.yml | 22 +++ .../gateway-dist/bin/startup.sh | 24 +++ .../gateway-dist/pom.xml | 54 +++++++ .../src/main/assembly/assembly.xml | 46 ++++++ .../gateway-projectA-scenario/pom.xml | 67 +++++++++ .../WebFluxSkyWalkingTraceContext.java | 79 ++++++++++ .../sc/gateway/projectA/ApiKeyResolver.java | 31 ++++ .../sc/gateway/projectA/Application.java | 29 ++++ .../sc/gateway/projectA/Test1Filter.java | 43 ++++++ .../sc/gateway/projectA/Test2Filter.java | 48 ++++++ .../sc/gateway/projectA/Test3Filter.java | 48 ++++++ .../sc/gateway/projectA/TestFilterConfig.java | 40 +++++ .../src/main/resources/application.yml | 29 ++++ .../gateway-projectB-scenario/pom.xml | 57 +++++++ .../apm/toolkit/trace/TraceContext.java | 76 ++++++++++ .../sc/gateway/projectB/Application.java | 31 ++++ .../projectB/controller/TestController.java | 117 +++++++++++++++ .../src/main/resources/application.properties | 17 +++ .../pom.xml | 59 ++++++++ .../support-version.list | 17 +++ 35 files changed, 1579 insertions(+), 22 deletions(-) create mode 100644 apm-application-toolkit/apm-toolkit-webflux/src/main/java/org/apache/skywalking/apm/toolkit/webflux/WebFluxSkyWalkingTraceContext.java create mode 100644 apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingCorrelationContextGetInterceptor.java create mode 100644 apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingCorrelationContextPutInterceptor.java create mode 100644 apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingSegmentIDInterceptor.java create mode 100644 apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingSpanIDInterceptor.java create mode 100644 apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingStaticMethodsAroundInterceptor.java create mode 100644 apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingTraceContextActivation.java create mode 100644 apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingTraceIDInterceptor.java create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/config/expectedData.yaml create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/configuration.yml create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-dist/bin/startup.sh create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-dist/pom.xml create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-dist/src/main/assembly/assembly.xml create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/pom.xml create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/org/apache/skywalking/apm/toolkit/webflux/WebFluxSkyWalkingTraceContext.java create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/ApiKeyResolver.java create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Application.java create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Test1Filter.java create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Test2Filter.java create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Test3Filter.java create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/TestFilterConfig.java create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/resources/application.yml create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/pom.xml create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/java/org/apache/skywalking/apm/toolkit/trace/TraceContext.java create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectB/Application.java create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectB/controller/TestController.java create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/resources/application.properties create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/pom.xml create mode 100644 test/plugin/scenarios/gateway-3.x-filter-context-scenario/support-version.list diff --git a/.github/workflows/plugins-test.3.yaml b/.github/workflows/plugins-test.3.yaml index 5d651642e6..a4cfe3cb54 100644 --- a/.github/workflows/plugins-test.3.yaml +++ b/.github/workflows/plugins-test.3.yaml @@ -90,6 +90,7 @@ jobs: - dbcp-2.x-scenario - jsonrpc4j-1.x-scenario - gateway-3.x-scenario + - gateway-3.x-filter-context-scenario - neo4j-4.x-scenario - oracle-scenario - druid-1.x-scenario diff --git a/CHANGES.md b/CHANGES.md index d8560ee0c9..40fe33c01f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -133,6 +133,7 @@ Callable { * Support Jdk17 ZGC metric collect * Support Jetty 11.x plugin +* Support access the sky-walking tracer context in spring gateway filter * Fix the scenario of using the HBase plugin with spring-data-hadoop. * Add RocketMQ 5.x plugin * Fix the conflict between the logging kernel and the JDK threadpool plugin. diff --git a/apm-application-toolkit/apm-toolkit-webflux/src/main/java/org/apache/skywalking/apm/toolkit/webflux/WebFluxSkyWalkingTraceContext.java b/apm-application-toolkit/apm-toolkit-webflux/src/main/java/org/apache/skywalking/apm/toolkit/webflux/WebFluxSkyWalkingTraceContext.java new file mode 100644 index 0000000000..82198edb5c --- /dev/null +++ b/apm-application-toolkit/apm-toolkit-webflux/src/main/java/org/apache/skywalking/apm/toolkit/webflux/WebFluxSkyWalkingTraceContext.java @@ -0,0 +1,79 @@ +/* + * 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.toolkit.webflux; + +import org.springframework.web.server.ServerWebExchange; + +import java.util.Optional; + +/** + * TraceContext for WebFlux. + */ +public class WebFluxSkyWalkingTraceContext { + /** + * Try to get the traceId of current trace context. + * + * @param serverWebExchange - EnhancedInstance that contains the tracing context + * @return traceId, if it exists, or empty {@link String}. + */ + public static String traceId(ServerWebExchange serverWebExchange) { + return ""; + } + + /** + * Try to get the segmentId of current trace context. + * + * @param serverWebExchange - EnhancedInstance that contains the tracing context + * @return segmentId, if it exists, or empty {@link String}. + */ + public static String segmentId(ServerWebExchange serverWebExchange) { + return ""; + } + + /** + * Try to get the spanId of current trace context. The spanId is a negative number when the trace context is + * missing. + * + * @param serverWebExchange - EnhancedInstance that contains the tracing context + * @return spanId, if it exists, or empty {@link String}. + */ + public static int spanId(ServerWebExchange serverWebExchange) { + return -1; + } + + /** + * Try to get the custom value from trace context. + * + * @param serverWebExchange - EnhancedInstance that contains the tracing context + * @return custom data value. + */ + public static Optional getCorrelation(ServerWebExchange serverWebExchange, String key) { + return Optional.empty(); + } + + /** + * Put the custom key/value into trace context. + * + * @param serverWebExchange - EnhancedInstance that contains the tracing context + * @return previous value if it exists. + */ + public static Optional putCorrelation(ServerWebExchange serverWebExchange, String key, String value) { + return Optional.empty(); + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/CorrelationContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/CorrelationContext.java index 658fb5fcb0..2b1356c28b 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/CorrelationContext.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/CorrelationContext.java @@ -19,11 +19,11 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import org.apache.skywalking.apm.agent.core.base64.Base64; import org.apache.skywalking.apm.agent.core.conf.Config; @@ -49,7 +49,7 @@ public class CorrelationContext { } public CorrelationContext() { - this.data = new HashMap<>(Config.Correlation.ELEMENT_MAX_NUMBER); + this.data = new ConcurrentHashMap<>(Config.Correlation.ELEMENT_MAX_NUMBER); } /** diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingCorrelationContextGetInterceptor.java b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingCorrelationContextGetInterceptor.java new file mode 100644 index 0000000000..73b06431e1 --- /dev/null +++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingCorrelationContextGetInterceptor.java @@ -0,0 +1,49 @@ +/* + * 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.toolkit.activation.webflux; + +import org.apache.skywalking.apm.agent.core.context.ContextSnapshot; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; + +import java.lang.reflect.Method; +import java.util.Optional; + +public class WebFluxSkyWalkingCorrelationContextGetInterceptor extends WebFluxSkyWalkingStaticMethodsAroundInterceptor { + + @Override + public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, MethodInterceptResult result) { + final ContextSnapshot contextSnapshot = getContextSnapshot(allArguments[0]); + if (contextSnapshot == null || contextSnapshot.getCorrelationContext() == null) { + return; + } + + final String key = (String) allArguments[1]; + final Optional data = contextSnapshot.getCorrelationContext().get(key); + + result.defineReturnValue(data); + } + + @Override + public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, Object ret) { + return ret; + } + + @Override + public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, Throwable t) { + } +} diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingCorrelationContextPutInterceptor.java b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingCorrelationContextPutInterceptor.java new file mode 100644 index 0000000000..49bc2a3658 --- /dev/null +++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingCorrelationContextPutInterceptor.java @@ -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.toolkit.activation.webflux; + +import org.apache.skywalking.apm.agent.core.context.ContextSnapshot; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; + +import java.lang.reflect.Method; +import java.util.Optional; + +public class WebFluxSkyWalkingCorrelationContextPutInterceptor extends WebFluxSkyWalkingStaticMethodsAroundInterceptor { + + @Override + public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, MethodInterceptResult result) { + final ContextSnapshot contextSnapshot = getContextSnapshot(allArguments[0]); + if (contextSnapshot == null || contextSnapshot.getCorrelationContext() == null) { + return; + } + + final String key = (String) allArguments[1]; + final String value = (String) allArguments[2]; + final Optional previous = contextSnapshot.getCorrelationContext().put(key, value); + + result.defineReturnValue(previous); + } + + @Override + public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, Object ret) { + return ret; + } + + @Override + public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, Throwable t) { + } +} diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingOperatorsInterceptor.java b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingOperatorsInterceptor.java index 679710700f..8ae39dfff8 100644 --- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingOperatorsInterceptor.java +++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingOperatorsInterceptor.java @@ -22,18 +22,15 @@ 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.MethodInterceptResult; -import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor; import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.server.ServerWebExchangeDecorator; -import org.springframework.web.server.adapter.DefaultServerWebExchange; import reactor.util.context.Context; import java.lang.reflect.Method; /** */ -public class WebFluxSkyWalkingOperatorsInterceptor implements StaticMethodsAroundInterceptor { +public class WebFluxSkyWalkingOperatorsInterceptor extends WebFluxSkyWalkingStaticMethodsAroundInterceptor { @Override public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, @@ -67,14 +64,4 @@ public void handleMethodException(Class clazz, Method method, Object[] allArgume ContextManager.activeSpan().log(t); } - private static EnhancedInstance getInstance(Object o) { - EnhancedInstance instance = null; - if (o instanceof DefaultServerWebExchange && o instanceof EnhancedInstance) { - instance = (EnhancedInstance) o; - } else if (o instanceof ServerWebExchangeDecorator) { - ServerWebExchange delegate = ((ServerWebExchangeDecorator) o).getDelegate(); - return getInstance(delegate); - } - return instance; - } } diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingSegmentIDInterceptor.java b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingSegmentIDInterceptor.java new file mode 100644 index 0000000000..a8dc12a80c --- /dev/null +++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingSegmentIDInterceptor.java @@ -0,0 +1,53 @@ +/* + * 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.toolkit.activation.webflux; + +import org.apache.skywalking.apm.agent.core.context.ContextSnapshot; +import org.apache.skywalking.apm.agent.core.logging.api.ILog; +import org.apache.skywalking.apm.agent.core.logging.api.LogManager; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; + +import java.lang.reflect.Method; + +public class WebFluxSkyWalkingSegmentIDInterceptor extends WebFluxSkyWalkingStaticMethodsAroundInterceptor { + + private static final ILog LOGGER = LogManager.getLogger(WebFluxSkyWalkingSegmentIDInterceptor.class); + + @Override + public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + MethodInterceptResult result) { + final ContextSnapshot contextSnapshot = getContextSnapshot(allArguments[0]); + if (contextSnapshot == null || contextSnapshot.getCorrelationContext() == null) { + return; + } + result.defineReturnValue(contextSnapshot.getTraceSegmentId()); + } + + @Override + public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + Object ret) { + return ret; + } + + @Override + public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + Throwable t) { + LOGGER.error("Failed to get segment Id.", t); + } +} diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingSpanIDInterceptor.java b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingSpanIDInterceptor.java new file mode 100644 index 0000000000..9055a707e8 --- /dev/null +++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingSpanIDInterceptor.java @@ -0,0 +1,53 @@ +/* + * 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.toolkit.activation.webflux; + +import org.apache.skywalking.apm.agent.core.context.ContextSnapshot; +import org.apache.skywalking.apm.agent.core.logging.api.ILog; +import org.apache.skywalking.apm.agent.core.logging.api.LogManager; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; + +import java.lang.reflect.Method; + +public class WebFluxSkyWalkingSpanIDInterceptor extends WebFluxSkyWalkingStaticMethodsAroundInterceptor { + + private static final ILog LOGGER = LogManager.getLogger(WebFluxSkyWalkingSpanIDInterceptor.class); + + @Override + public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + MethodInterceptResult result) { + final ContextSnapshot contextSnapshot = getContextSnapshot(allArguments[0]); + if (contextSnapshot == null || contextSnapshot.getCorrelationContext() == null) { + return; + } + result.defineReturnValue(contextSnapshot.getSpanId()); + } + + @Override + public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + Object ret) { + return ret; + } + + @Override + public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + Throwable t) { + LOGGER.error("Failed to getDefault span Id.", t); + } +} diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingStaticMethodsAroundInterceptor.java b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingStaticMethodsAroundInterceptor.java new file mode 100644 index 0000000000..138d9440eb --- /dev/null +++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingStaticMethodsAroundInterceptor.java @@ -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.toolkit.activation.webflux; + +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.StaticMethodsAroundInterceptor; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.ServerWebExchangeDecorator; +import org.springframework.web.server.adapter.DefaultServerWebExchange; + +import java.util.Optional; + +public abstract class WebFluxSkyWalkingStaticMethodsAroundInterceptor implements StaticMethodsAroundInterceptor { + + protected EnhancedInstance getInstance(Object o) { + EnhancedInstance instance = null; + if (o instanceof DefaultServerWebExchange && o instanceof EnhancedInstance) { + instance = (EnhancedInstance) o; + } else if (o instanceof ServerWebExchangeDecorator) { + ServerWebExchange delegate = ((ServerWebExchangeDecorator) o).getDelegate(); + return getInstance(delegate); + } + return instance; + } + + protected ContextSnapshot getContextSnapshot(Object o) { + return Optional.ofNullable(getInstance(o)) + .map(EnhancedInstance::getSkyWalkingDynamicField) + .filter(ContextSnapshot.class::isInstance) + .map(ContextSnapshot.class::cast) + .orElse(null); + } +} diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingTraceContextActivation.java b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingTraceContextActivation.java new file mode 100644 index 0000000000..77d522f740 --- /dev/null +++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingTraceContextActivation.java @@ -0,0 +1,142 @@ +/* + * 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.toolkit.activation.webflux; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassStaticMethodsEnhancePluginDefine; +import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; +import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class WebFluxSkyWalkingTraceContextActivation extends ClassStaticMethodsEnhancePluginDefine { + + public static final String TRACE_ID_INTERCEPT_CLASS = "org.apache.skywalking.apm.toolkit.activation.webflux.WebFluxSkyWalkingTraceIDInterceptor"; + public static final String SEGMENT_ID_INTERCEPT_CLASS = "org.apache.skywalking.apm.toolkit.activation.webflux.WebFluxSkyWalkingSegmentIDInterceptor"; + public static final String SPAN_ID_INTERCEPT_CLASS = "org.apache.skywalking.apm.toolkit.activation.webflux.WebFluxSkyWalkingSpanIDInterceptor"; + public static final String ENHANCE_CLASS = "org.apache.skywalking.apm.toolkit.webflux.WebFluxSkyWalkingTraceContext"; + public static final String ENHANCE_TRACE_ID_METHOD = "traceId"; + public static final String ENHANCE_SEGMENT_ID_METHOD = "segmentId"; + public static final String ENHANCE_SPAN_ID_METHOD = "spanId"; + public static final String ENHANCE_GET_CORRELATION_METHOD = "getCorrelation"; + public static final String INTERCEPT_GET_CORRELATION_CLASS = "org.apache.skywalking.apm.toolkit.activation.webflux.WebFluxSkyWalkingCorrelationContextGetInterceptor"; + public static final String ENHANCE_PUT_CORRELATION_METHOD = "putCorrelation"; + public static final String INTERCEPT_PUT_CORRELATION_CLASS = "org.apache.skywalking.apm.toolkit.activation.webflux.WebFluxSkyWalkingCorrelationContextPutInterceptor"; + + /** + * @return the target class, which needs active. + */ + @Override + protected ClassMatch enhanceClass() { + return NameMatch.byName(ENHANCE_CLASS); + } + + /** + * @return the collection of {@link StaticMethodsInterceptPoint}, represent the intercepted methods and their + * interceptors. + */ + @Override + public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() { + return new StaticMethodsInterceptPoint[] { + new StaticMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return named(ENHANCE_TRACE_ID_METHOD); + } + + @Override + public String getMethodsInterceptor() { + return TRACE_ID_INTERCEPT_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + }, + new StaticMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return named(ENHANCE_SEGMENT_ID_METHOD); + } + + @Override + public String getMethodsInterceptor() { + return SEGMENT_ID_INTERCEPT_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + }, + new StaticMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return named(ENHANCE_SPAN_ID_METHOD); + } + + @Override + public String getMethodsInterceptor() { + return SPAN_ID_INTERCEPT_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + }, + + new StaticMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return named(ENHANCE_GET_CORRELATION_METHOD); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPT_GET_CORRELATION_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + }, + new StaticMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return named(ENHANCE_PUT_CORRELATION_METHOD); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPT_PUT_CORRELATION_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } +} diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingTraceIDInterceptor.java b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingTraceIDInterceptor.java new file mode 100644 index 0000000000..c3b53ecea4 --- /dev/null +++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/java/org/apache/skywalking/apm/toolkit/activation/webflux/WebFluxSkyWalkingTraceIDInterceptor.java @@ -0,0 +1,53 @@ +/* + * 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.toolkit.activation.webflux; + +import org.apache.skywalking.apm.agent.core.context.ContextSnapshot; +import org.apache.skywalking.apm.agent.core.logging.api.ILog; +import org.apache.skywalking.apm.agent.core.logging.api.LogManager; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; + +import java.lang.reflect.Method; + +public class WebFluxSkyWalkingTraceIDInterceptor extends WebFluxSkyWalkingStaticMethodsAroundInterceptor { + + private static final ILog LOGGER = LogManager.getLogger(WebFluxSkyWalkingTraceIDInterceptor.class); + + @Override + public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + MethodInterceptResult result) { + final ContextSnapshot contextSnapshot = getContextSnapshot(allArguments[0]); + if (contextSnapshot == null || contextSnapshot.getCorrelationContext() == null) { + return; + } + result.defineReturnValue(contextSnapshot.getTraceId().getId()); + } + + @Override + public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + Object ret) { + return ret; + } + + @Override + public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, + Throwable t) { + LOGGER.error("Failed to getDefault trace Id.", t); + } +} diff --git a/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/resources/skywalking-plugin.def index de46b3ce11..660b453807 100644 --- a/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/resources/skywalking-plugin.def +++ b/apm-sniffer/apm-toolkit-activation/apm-toolkit-webflux-activation/src/main/resources/skywalking-plugin.def @@ -14,4 +14,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -toolkit-webflux=org.apache.skywalking.apm.toolkit.activation.webflux.WebFluxSkyWalkingOperatorsActivation \ No newline at end of file +toolkit-webflux=org.apache.skywalking.apm.toolkit.activation.webflux.WebFluxSkyWalkingOperatorsActivation +toolkit-webflux=org.apache.skywalking.apm.toolkit.activation.webflux.WebFluxSkyWalkingTraceContextActivation \ No newline at end of file diff --git a/docs/en/setup/service-agent/java-agent/Application-toolkit-webflux.md b/docs/en/setup/service-agent/java-agent/Application-toolkit-webflux.md index 32a2662384..0fa738c54c 100644 --- a/docs/en/setup/service-agent/java-agent/Application-toolkit-webflux.md +++ b/docs/en/setup/service-agent/java-agent/Application-toolkit-webflux.md @@ -1,5 +1,8 @@ -# Mannual propagation of tracing context for Webflux -* Dependency the toolkit, such as using maven or gradle +# Webflux Tracing Assistant APIs + +These APIs provide advanced features to enhance interaction capabilities in Webflux cases. + +Add the toolkit to your project dependency, through Maven or Gradle ```xml org.apache.skywalking @@ -8,7 +11,11 @@ ``` -* usage 1. +The following scenarios are supported for tracing assistance. + +### Continue Tracing from Client +The `WebFluxSkyWalkingOperators#continueTracing` provides manual tracing continuous capabilities to adopt native Webflux APIs + ```java @GetMapping("/testcase/annotation/mono/onnext") public Mono monoOnNext(@RequestBody(required = false) String body) { @@ -19,7 +26,7 @@ })); } ``` -* usage 2. + ```java @GetMapping("/login/userFunctions") public Mono> functionInfo(ServerWebExchange exchange, @RequestParam String userId) { @@ -34,7 +41,6 @@ } ``` -* usage 3. ```java Mono.just("key").subscribeOn(Schedulers.boundedElastic()) .doOnEach(WebFluxSkyWalkingOperators.continueTracing(SignalType.ON_NEXT, () -> log.info("test log with tid"))) @@ -46,6 +52,40 @@ ... ``` +### Fetch trace context relative IDs +```java + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain){ + // fetch trace ID + String traceId = WebFluxSkyWalkingTraceContext.traceId(exchange); + + // fetch segment ID + String segmentId = WebFluxSkyWalkingTraceContext.segmentId(exchange); + + // fetch span ID + int spanId = WebFluxSkyWalkingTraceContext.spanId(exchange); + + return chain.filter(exchange); + } +``` + +### Manipulate Correlation Context + +```java + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain){ + // Set correlation data can be retrieved by upstream nodes. + WebFluxSkyWalkingTraceContext.putCorrelation(exchange, "key1", "value"); + + // Get correlation data + Optional value2 = WebFluxSkyWalkingTraceContext.getCorrelation(exchange, "key2"); + + // dosomething... + + return chain.filter(exchange); + } +``` + _Sample codes only_ diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/config/expectedData.yaml b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/config/expectedData.yaml new file mode 100644 index 0000000000..61852cba38 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/config/expectedData.yaml @@ -0,0 +1,64 @@ +# 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/b/context + parentSpanId: 0 + spanId: 1 + isError: false + spanType: Exit + tags: + - { key: url, value: not null } + - { key: http.method, value: GET } + - { key: http.status_code, value: '200' } + - operationName: GET:/provider/b/testcase + parentSpanId: -1 + spanId: 0 + spanLayer: Http + startTime: nq 0 + endTime: nq 0 + componentId: 14 + isError: false + spanType: Entry + peer: '' + tags: + - {key: url, value: not null} + - {key: http.method, value: GET} + - {key: http.status_code, value: '200'} + refs: + - {parentEndpoint: SpringCloudGateway/RoutingFilter, networkAddress: 'localhost:18070', + refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not + null, parentService: not null, traceId: not null} + skipAnalysis: 'false' +- serviceName: gateway-projectA-scenario + segmentSize: nq 0 + segments: + - segmentId: not null + spans: + - operationName: /provider/b/context + parentSpanId: -1 + spanId: 0 + spanLayer: Http + isError: false + spanType: Entry + tags: + - {key: url, value: 'http://localhost:8080/provider/b/context' } + - {key: http.method, value: GET} + - {key: http.status_code, value: '200'} \ No newline at end of file diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/configuration.yml b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/configuration.yml new file mode 100644 index 0000000000..1e81d708a5 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/configuration.yml @@ -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-3.x-plugin-*.jar;apm-spring-webflux-5.x-plugin-*.jar diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-dist/bin/startup.sh b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-dist/bin/startup.sh new file mode 100644 index 0000000000..0d28675632 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-dist/bin/startup.sh @@ -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 & diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-dist/pom.xml b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-dist/pom.xml new file mode 100644 index 0000000000..37f4011509 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-dist/pom.xml @@ -0,0 +1,54 @@ + + + + + org.apache.skywalking + gateway-3.x-filter-context-scenario + 5.0.0 + + 4.0.0 + + gateway-dist + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + assemble + package + + single + + + + src/main/assembly/assembly.xml + + ../target/ + + + + + + + diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-dist/src/main/assembly/assembly.xml b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-dist/src/main/assembly/assembly.xml new file mode 100644 index 0000000000..00d04e28e0 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-dist/src/main/assembly/assembly.xml @@ -0,0 +1,46 @@ + + + + + zip + + + + + ./bin + 0775 + + + + + + ../gateway-projectA-scenario/target/gateway-projectA-scenario.jar + ./libs + 0775 + + + ../gateway-projectB-scenario/target/gateway-projectB-scenario.jar + ./libs + 0775 + + + \ No newline at end of file diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/pom.xml b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/pom.xml new file mode 100644 index 0000000000..1056776972 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/pom.xml @@ -0,0 +1,67 @@ + + + + + org.apache.skywalking + gateway-3.x-filter-context-scenario + 5.0.0 + + 4.0.0 + + gateway-projectA-scenario + + + + org.springframework.cloud + spring-cloud-starter-gateway + ${test.framework.version} + + + + + gateway-projectA-scenario + + + org.springframework.boot + spring-boot-maven-plugin + 1.5.9.RELEASE + + + + repackage + + + + + + + + + + spring-snapshots + https://repo.spring.io/snapshot + + + spring-milestones + https://repo.spring.io/milestone + + + diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/org/apache/skywalking/apm/toolkit/webflux/WebFluxSkyWalkingTraceContext.java b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/org/apache/skywalking/apm/toolkit/webflux/WebFluxSkyWalkingTraceContext.java new file mode 100644 index 0000000000..82198edb5c --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/org/apache/skywalking/apm/toolkit/webflux/WebFluxSkyWalkingTraceContext.java @@ -0,0 +1,79 @@ +/* + * 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.toolkit.webflux; + +import org.springframework.web.server.ServerWebExchange; + +import java.util.Optional; + +/** + * TraceContext for WebFlux. + */ +public class WebFluxSkyWalkingTraceContext { + /** + * Try to get the traceId of current trace context. + * + * @param serverWebExchange - EnhancedInstance that contains the tracing context + * @return traceId, if it exists, or empty {@link String}. + */ + public static String traceId(ServerWebExchange serverWebExchange) { + return ""; + } + + /** + * Try to get the segmentId of current trace context. + * + * @param serverWebExchange - EnhancedInstance that contains the tracing context + * @return segmentId, if it exists, or empty {@link String}. + */ + public static String segmentId(ServerWebExchange serverWebExchange) { + return ""; + } + + /** + * Try to get the spanId of current trace context. The spanId is a negative number when the trace context is + * missing. + * + * @param serverWebExchange - EnhancedInstance that contains the tracing context + * @return spanId, if it exists, or empty {@link String}. + */ + public static int spanId(ServerWebExchange serverWebExchange) { + return -1; + } + + /** + * Try to get the custom value from trace context. + * + * @param serverWebExchange - EnhancedInstance that contains the tracing context + * @return custom data value. + */ + public static Optional getCorrelation(ServerWebExchange serverWebExchange, String key) { + return Optional.empty(); + } + + /** + * Put the custom key/value into trace context. + * + * @param serverWebExchange - EnhancedInstance that contains the tracing context + * @return previous value if it exists. + */ + public static Optional putCorrelation(ServerWebExchange serverWebExchange, String key, String value) { + return Optional.empty(); + } +} diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/ApiKeyResolver.java b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/ApiKeyResolver.java new file mode 100644 index 0000000000..40517d1d3f --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/ApiKeyResolver.java @@ -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 resolve(ServerWebExchange exchange) { + return Mono.just(exchange.getRequest().getPath().value()); + } +} diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Application.java b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Application.java new file mode 100644 index 0000000000..68eb95b0c6 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Application.java @@ -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); + } +} diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Test1Filter.java b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Test1Filter.java new file mode 100644 index 0000000000..32a4d4d809 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Test1Filter.java @@ -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 test.apache.skywalking.apm.testcase.sc.gateway.projectA; + +import org.apache.skywalking.apm.toolkit.webflux.WebFluxSkyWalkingTraceContext; +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 filter(ServerWebExchange exchange, GatewayFilterChain chain) { + + WebFluxSkyWalkingTraceContext.putCorrelation(exchange, "custom-data1", + exchange.getRequest().getHeaders().getFirst("x-custom-data1")); + + ServerHttpRequest buildRequest = exchange.getRequest().mutate().build(); + return chain.filter(exchange.mutate().request(buildRequest).build()); + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Test2Filter.java b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Test2Filter.java new file mode 100644 index 0000000000..2b8f780ec7 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Test2Filter.java @@ -0,0 +1,48 @@ +/* + * 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.apache.skywalking.apm.toolkit.webflux.WebFluxSkyWalkingTraceContext; +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; + +import java.util.Optional; + +public class Test2Filter implements GlobalFilter, Ordered { + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + + Optional data1 = WebFluxSkyWalkingTraceContext.getCorrelation(exchange, "custom-data1"); + + WebFluxSkyWalkingTraceContext.putCorrelation(exchange, "custom-data2", + data1.orElse("") + ";" + exchange.getRequest().getHeaders().getFirst("x-custom-data2")); + + ServerHttpRequest buildRequest = exchange.getRequest().mutate().build(); + return chain.filter(exchange.mutate().request(buildRequest).build()); + } + + @Override + public int getOrder() { + return 1; + } +} diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Test3Filter.java b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Test3Filter.java new file mode 100644 index 0000000000..58ee0b9b38 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/Test3Filter.java @@ -0,0 +1,48 @@ +/* + * 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.apache.skywalking.apm.toolkit.webflux.WebFluxSkyWalkingTraceContext; +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 Test3Filter implements GlobalFilter, Ordered { + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + + ServerHttpRequest buildRequest = exchange.getRequest() + .mutate() + .headers(httpHeaders -> { + httpHeaders.add("x-trace-id", WebFluxSkyWalkingTraceContext.traceId(exchange)); + httpHeaders.add("x-segment-id", WebFluxSkyWalkingTraceContext.segmentId(exchange)); + httpHeaders.add("x-span-id", String.valueOf(WebFluxSkyWalkingTraceContext.spanId(exchange))); + }) + .build(); + return chain.filter(exchange.mutate().request(buildRequest).build()); + } + + @Override + public int getOrder() { + return 2; + } +} diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/TestFilterConfig.java b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/TestFilterConfig.java new file mode 100644 index 0000000000..fb83b75c02 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectA/TestFilterConfig.java @@ -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.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(); + } + + @Bean + public Test3Filter test3Filter() { + return new Test3Filter(); + } +} diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/resources/application.yml b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/resources/application.yml new file mode 100644 index 0000000000..5836ff87b2 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectA-scenario/src/main/resources/application.yml @@ -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. +# + +server: + port: 8080 +spring: + cloud: + gateway: + httpclient: + connect-timeout: 2000 + routes: + - id: provider_route + uri: http://localhost:18070 + predicates: + - Path=/provider/b/* diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/pom.xml b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/pom.xml new file mode 100644 index 0000000000..dd9752365d --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/pom.xml @@ -0,0 +1,57 @@ + + + + + gateway-3.x-filter-context-scenario + org.apache.skywalking + 5.0.0 + + 4.0.0 + + gateway-projectB-scenario + + + + org.springframework.boot + spring-boot-starter-web + 2.1.0.RELEASE + + + + + gateway-projectB-scenario + + + org.springframework.boot + spring-boot-maven-plugin + 1.5.9.RELEASE + + + + repackage + + + + + + + + \ No newline at end of file diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/java/org/apache/skywalking/apm/toolkit/trace/TraceContext.java b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/java/org/apache/skywalking/apm/toolkit/trace/TraceContext.java new file mode 100644 index 0000000000..dd191c16a0 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/java/org/apache/skywalking/apm/toolkit/trace/TraceContext.java @@ -0,0 +1,76 @@ +/* + * 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.toolkit.trace; + +import java.util.Optional; + +/** + * Try to access the sky-walking tracer context. The context is not existed, always. only the middleware, component, or + * rpc-framework are supported in the current invoke stack, in the same thread, the context will be available. + *

+ */ +public class TraceContext { + + /** + * Try to get the traceId of current trace context. + * + * @return traceId, if it exists, or empty {@link String}. + */ + public static String traceId() { + return ""; + } + + /** + * Try to get the segmentId of current trace context. + * + * @return segmentId, if it exists, or empty {@link String}. + */ + public static String segmentId() { + return ""; + } + + /** + * Try to get the spanId of current trace context. The spanId is a negative number when the trace context is + * missing. + * + * @return spanId, if it exists, or empty {@link String}. + */ + public static int spanId() { + return -1; + } + + /** + * Try to get the custom value from trace context. + * + * @return custom data value. + */ + public static Optional getCorrelation(String key) { + return Optional.empty(); + } + + /** + * Put the custom key/value into trace context. + * + * @return previous value if it exists. + */ + public static Optional putCorrelation(String key, String value) { + return Optional.empty(); + } + +} diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectB/Application.java b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectB/Application.java new file mode 100644 index 0000000000..51c94655c7 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectB/Application.java @@ -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); + } +} diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectB/controller/TestController.java b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectB/controller/TestController.java new file mode 100644 index 0000000000..75c5cef354 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/gateway/projectB/controller/TestController.java @@ -0,0 +1,117 @@ +/* + * 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.apache.skywalking.apm.toolkit.trace.TraceContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import java.net.URI; +import java.util.Map; +import java.util.Random; + +@RestController +public class TestController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + static String randomString(int length) { + String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + int strLen = str.length(); + Random random = new Random(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + int number = random.nextInt(strLen); + sb.append(str.charAt(number)); + } + return sb.toString(); + } + + @RequestMapping("/provider/b/testcase") + public String testcase() { + + String d1 = randomString(10); + String d2 = randomString(13); + + RequestEntity requestEntity = RequestEntity.get(URI.create("http://localhost:8080/provider/b/context")) + .header("x-custom-data1", d1) + .header("x-custom-data2", d2) + .build(); + + logger.info("requestEntity: {}", requestEntity); + + ResponseEntity response = new RestTemplate().exchange(requestEntity, String.class); + + logger.info("response: {}", response); + + if (!response.getStatusCode().is2xxSuccessful()) { + throw new IllegalStateException("response status code is not 2xx"); + } + + String body = response.getBody(); + if (StringUtils.isEmpty(body)) { + throw new IllegalStateException("response body is empty"); + } + + if (!checkResponseBody(d1, d2, body)) { + throw new IllegalStateException("response body is not expected"); + } + + return "1"; + } + + private boolean checkResponseBody(String d1, String d2, String body) { + String[] lines = body.split("\n"); + return lines.length == 2 && (lines[0].equals(d1) && lines[1].equals(d1 + ";" + d2)); + } + + @RequestMapping("/provider/b/context") + public String context(@RequestHeader Map headers) { + + String traceIdInHeader = headers.get("x-trace-id"); + + logger.info("traceId:{} vs {}", TraceContext.traceId(), traceIdInHeader); + + if (!TraceContext.traceId().equals(traceIdInHeader)) { + throw new IllegalStateException("response header x-trace-id is not expected"); + } + + if (StringUtils.isEmpty(headers.get("x-segment-id"))) { + throw new IllegalStateException("response header x-segment-id is empty"); + } + + if (StringUtils.isEmpty(headers.get("x-span-id"))) { + throw new IllegalStateException("response header x-span-id is empty"); + } + + return TraceContext.getCorrelation("custom-data1").orElse("") + "\n" + + TraceContext.getCorrelation("custom-data2").orElse(""); + } + + @RequestMapping("/provider/b/healthCheck") + public String healthCheck() { + return "Success"; + } +} diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/resources/application.properties b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/resources/application.properties new file mode 100644 index 0000000000..cac2c4d5a1 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/gateway-projectB-scenario/src/main/resources/application.properties @@ -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 \ No newline at end of file diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/pom.xml b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/pom.xml new file mode 100644 index 0000000000..97851b0090 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/pom.xml @@ -0,0 +1,59 @@ + + + + 4.0.0 + + org.apache.skywalking + gateway-3.x-filter-context-scenario + pom + 5.0.0 + + gateway-projectA-scenario + gateway-projectB-scenario + gateway-dist + + + skywalking-gateway-3.x-filter-context-scenario + + + UTF-8 + 1.8 + 3.8.1 + 3.0.0 + ${test.framework.version} + + + + gateway-3.x-filter-context-scenario + + + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${compiler.version} + ${compiler.version} + ${project.build.sourceEncoding} + + + + + + diff --git a/test/plugin/scenarios/gateway-3.x-filter-context-scenario/support-version.list b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/support-version.list new file mode 100644 index 0000000000..3662698b83 --- /dev/null +++ b/test/plugin/scenarios/gateway-3.x-filter-context-scenario/support-version.list @@ -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. + +3.0.0 \ No newline at end of file