wu-sheng closed pull request #1993: Support webflux and spring mvc 5 plugin URL: https://github.com/apache/incubator-skywalking/pull/1993
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/RuntimeContextConfiguration.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/RuntimeContextConfiguration.java index f1b95a3ca1..ae7380939e 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/RuntimeContextConfiguration.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/RuntimeContextConfiguration.java @@ -23,6 +23,7 @@ public static String[] NEED_PROPAGATE_CONTEXT_KEY = new String[] { "SW_REQUEST", - "SW_RESPONSE" + "SW_RESPONSE", + "SW_WEBFLUX_REQUEST_KEY" }; } diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v4/define/AbstractSpring4Instrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v4/define/AbstractSpring4Instrumentation.java index 1d66adff7a..bf891d53f3 100644 --- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v4/define/AbstractSpring4Instrumentation.java +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v4/define/AbstractSpring4Instrumentation.java @@ -22,10 +22,10 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; public abstract class AbstractSpring4Instrumentation extends ClassInstanceMethodsEnhancePluginDefine { - public static final String WITHNESS_CLASSES = "org.springframework.web.servlet.tags.ArgumentTag"; + public static final String WITHNESS_CLASSES = "org.springframework.cache.interceptor.SimpleKey"; @Override protected final String[] witnessClasses() { - return new String[] {WITHNESS_CLASSES}; + return new String[] {WITHNESS_CLASSES, "org.springframework.cache.interceptor.DefaultKeyGenerator"}; } } diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/pom.xml new file mode 100644 index 0000000000..9f94946861 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/pom.xml @@ -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. + --> + +<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>spring-plugins</artifactId> + <groupId>org.apache.skywalking</groupId> + <version>6.0.0-beta-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>apm-springmvc-annotation-5.x-plugin</artifactId> + <packaging>jar</packaging> + + <name>mvc-annotation-5.x-plugin</name> + <url>http://maven.apache.org</url> + + <properties> + <spring-core.version>5.0.0.RELEASE</spring-core.version> + <spring-webmvc.version>5.0.0.RELEASE</spring-webmvc.version> + <javax-servlet-api.version>3.0.1</javax-servlet-api.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-core</artifactId> + <version>${spring-core.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-webmvc</artifactId> + <version>${spring-webmvc.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <version>${javax-servlet-api.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.skywalking</groupId> + <artifactId>apm-springmvc-annotation-commons</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> +</project> diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/ControllerConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/ControllerConstructorInterceptor.java new file mode 100644 index 0000000000..f32ca40638 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/ControllerConstructorInterceptor.java @@ -0,0 +1,58 @@ +/* + * 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.mvc.v5; + +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.plugin.spring.mvc.commons.EnhanceRequireObjectCache; +import org.apache.skywalking.apm.plugin.spring.mvc.commons.PathMappingCache; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * The <code>ControllerConstructorInterceptor</code> intercepts the Controller's constructor, in order to acquire the + * mapping annotation, if exist. + * + * But, you can see we only use the first mapping value, <B>Why?</B> + * + * Right now, we intercept the controller by annotation as you known, so we CAN'T know which uri patten is actually + * matched. Even we know, that costs a lot. + * + * If we want to resolve that, we must intercept the Spring MVC core codes, that is not a good choice for now. + * + * Comment by @wu-sheng + */ +public class ControllerConstructorInterceptor implements InstanceConstructorInterceptor { + + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + String basePath = ""; + RequestMapping basePathRequestMapping = objInst.getClass().getAnnotation(RequestMapping.class); + if (basePathRequestMapping != null) { + if (basePathRequestMapping.value().length > 0) { + basePath = basePathRequestMapping.value()[0]; + } else if (basePathRequestMapping.path().length > 0) { + basePath = basePathRequestMapping.path()[0]; + } + } + EnhanceRequireObjectCache enhanceRequireObjectCache = new EnhanceRequireObjectCache(); + enhanceRequireObjectCache.setPathMappingCache(new PathMappingCache(basePath)); + objInst.setSkyWalkingDynamicField(enhanceRequireObjectCache); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/GetBeanInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/GetBeanInterceptor.java new file mode 100644 index 0000000000..a2e2144b0e --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/GetBeanInterceptor.java @@ -0,0 +1,59 @@ +/* + * 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.mvc.v5; + +import java.lang.reflect.Method; +import org.apache.skywalking.apm.agent.core.context.ContextManager; +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.context.request.NativeWebRequest; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.REQUEST_KEY_IN_RUNTIME_CONTEXT; +import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.RESPONSE_KEY_IN_RUNTIME_CONTEXT; + +/** + * {@link GetBeanInterceptor} pass the {@link NativeWebRequest} object into the {@link + * org.springframework.stereotype.Controller} object. + * + * @author zhangxin + */ +public class GetBeanInterceptor 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) { + ContextManager.getRuntimeContext().put(REQUEST_KEY_IN_RUNTIME_CONTEXT, ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest()); + ContextManager.getRuntimeContext().put(RESPONSE_KEY_IN_RUNTIME_CONTEXT, ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse()); + } + return ret; + } + + @Override + public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class<?>[] argumentsTypes, Throwable t) { + + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/AbstractControllerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/AbstractControllerInstrumentation.java new file mode 100644 index 0000000000..5fe377563d --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/AbstractControllerInstrumentation.java @@ -0,0 +1,113 @@ +/* + * 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.mvc.v5.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.DeclaredInstanceMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch; +import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; +import org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants; + +import static net.bytebuddy.matcher.ElementMatchers.*; + +/** + * {@link ControllerInstrumentation} enhance all constructor and method annotated with + * <code>org.springframework.web.bind.annotation.RequestMapping</code> that class has + * <code>org.springframework.stereotype.Controller</code> annotation. + * + * <code>ControllerConstructorInterceptor</code> set the controller base path to + * dynamic field before execute constructor. + * + * <code>org.apache.skywalking.apm.plugin.spring.mvc.v4.RequestMappingMethodInterceptor</code> get the request path from + * dynamic field first, if not found, <code>RequestMappingMethodInterceptor</code> generate request path that + * combine the path value of current annotation on current method and the base path and set the new path to the dynamic + * filed + * + * @author zhangxin + */ +public abstract class AbstractControllerInstrumentation extends AbstractSpring5Instrumentation { + @Override + protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[] { + new ConstructorInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getConstructorMatcher() { + return any(); + } + + @Override + public String getConstructorInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.mvc.v5.ControllerConstructorInterceptor"; + } + } + }; + } + + @Override + protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new DeclaredInstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return isAnnotatedWith(named("org.springframework.web.bind.annotation.RequestMapping")); + } + + @Override + public String getMethodsInterceptor() { + return Constants.REQUEST_MAPPING_METHOD_INTERCEPTOR; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + }, + new DeclaredInstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return isAnnotatedWith(named("org.springframework.web.bind.annotation.GetMapping")) + .or(isAnnotatedWith(named("org.springframework.web.bind.annotation.PostMapping"))) + .or(isAnnotatedWith(named("org.springframework.web.bind.annotation.PutMapping"))) + .or(isAnnotatedWith(named("org.springframework.web.bind.annotation.DeleteMapping"))) + .or(isAnnotatedWith(named("org.springframework.web.bind.annotation.PatchMapping"))); + } + + @Override + public String getMethodsInterceptor() { + return Constants.REST_MAPPING_METHOD_INTERCEPTOR; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override + protected ClassMatch enhanceClass() { + return ClassAnnotationMatch.byClassAnnotationMatch(getEnhanceAnnotations()); + } + + protected abstract String[] getEnhanceAnnotations(); + +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/AbstractSpring5Instrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/AbstractSpring5Instrumentation.java new file mode 100644 index 0000000000..e7126c871b --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/AbstractSpring5Instrumentation.java @@ -0,0 +1,30 @@ +/* + * 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.mvc.v5.define; + +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; + +public abstract class AbstractSpring5Instrumentation extends ClassInstanceMethodsEnhancePluginDefine { + public static final String WITHNESS_CLASSES = "org.springframework.web.servlet.resource.HttpResource"; + + @Override + protected final String[] witnessClasses() { + return new String[] {WITHNESS_CLASSES}; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/ControllerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/ControllerInstrumentation.java new file mode 100644 index 0000000000..c0643382a3 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/ControllerInstrumentation.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.skywalking.apm.plugin.spring.mvc.v5.define; + +public class ControllerInstrumentation extends AbstractControllerInstrumentation { + + public static final String ENHANCE_ANNOTATION = "org.springframework.stereotype.Controller"; + + @Override protected String[] getEnhanceAnnotations() { + return new String[] {ENHANCE_ANNOTATION}; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/HandlerMethodInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/HandlerMethodInstrumentation.java new file mode 100644 index 0000000000..537c3c43c9 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/HandlerMethodInstrumentation.java @@ -0,0 +1,71 @@ +/* + * 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.mvc.v5.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.NameMatch; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +/** + * {@link HandlerMethodInstrumentation} intercept the <code>getBean</code> method in the + * <code>org.springframework.web.method.HandlerMethod</code> class. + * + * @author zhangxin + */ +public class HandlerMethodInstrumentation extends AbstractSpring5Instrumentation { + + public static final String ENHANCE_METHOD = "getBean"; + public static final String ENHANCE_CLASS = "org.springframework.web.method.HandlerMethod"; + + @Override + protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[0]; + } + + @Override + protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named(ENHANCE_METHOD); + } + + @Override + public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.mvc.v5.GetBeanInterceptor"; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override + protected ClassMatch enhanceClass() { + return NameMatch.byName(ENHANCE_CLASS); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/RestControllerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/RestControllerInstrumentation.java new file mode 100644 index 0000000000..a7ae800c3e --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/RestControllerInstrumentation.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 org.apache.skywalking.apm.plugin.spring.mvc.v5.define; + +public class RestControllerInstrumentation extends AbstractControllerInstrumentation { + + public static final String ENHANCE_ANNOTATION = "org.springframework.web.bind.annotation.RestController"; + + @Override protected String[] getEnhanceAnnotations() { + return new String[] {ENHANCE_ANNOTATION}; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/resources/skywalking-plugin.def new file mode 100644 index 0000000000..fa3b452c17 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/resources/skywalking-plugin.def @@ -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. + +spring-mvc-annotation-5.x=org.apache.skywalking.apm.plugin.spring.mvc.v5.define.ControllerInstrumentation +spring-mvc-annotation-5.x=org.apache.skywalking.apm.plugin.spring.mvc.v5.define.RestControllerInstrumentation +spring-mvc-annotation-5.x=org.apache.skywalking.apm.plugin.spring.mvc.v5.define.HandlerMethodInstrumentation \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/Constants.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/Constants.java index 1ac245018e..114f8c2d4e 100644 --- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/Constants.java +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/Constants.java @@ -37,4 +37,6 @@ public static final String RESPONSE_KEY_IN_RUNTIME_CONTEXT = "SW_RESPONSE"; public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG"; + + public static final String WEBFLUX_REQUEST_KEY = "SW_WEBFLUX_REQUEST_KEY"; } diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml index b83eea8617..d9eef03719 100644 --- a/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml @@ -36,6 +36,8 @@ <module>core-patch</module> <module>mvc-annotation-commons</module> <module>spring-commons</module> + <module>mvc-annotation-5.x-plugin</module> + <module>webflux-5.x-plugin</module> </modules> <packaging>pom</packaging> diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/pom.xml new file mode 100644 index 0000000000..ba2fabd1b5 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/pom.xml @@ -0,0 +1,59 @@ +<!-- + ~ 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>spring-plugins</artifactId> + <groupId>org.apache.skywalking</groupId> + <version>6.0.0-beta-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>apm-webflux-5.x-plugin</artifactId> + <packaging>jar</packaging> + + <name>webflux-5.x-plugin</name> + <url>http://maven.apache.org</url> + + <properties> + <javax-servlet-api.version>3.0.1</javax-servlet-api.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-webflux</artifactId> + <version>5.0.0.RELEASE</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <version>${javax-servlet-api.version}</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.apache.skywalking</groupId> + <artifactId>apm-springmvc-annotation-commons</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> +</project> diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/AbstractMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/AbstractMethodInterceptor.java new file mode 100644 index 0000000000..da9dae605f --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/AbstractMethodInterceptor.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.skywalking.apm.plugin.spring.webflux.v5; + +import io.netty.handler.codec.http.HttpRequest; +import java.lang.reflect.Method; +import org.apache.skywalking.apm.agent.core.context.CarrierItem; +import org.apache.skywalking.apm.agent.core.context.ContextCarrier; +import org.apache.skywalking.apm.agent.core.context.ContextManager; +import org.apache.skywalking.apm.agent.core.context.tag.Tags; +import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; +import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; +import org.apache.skywalking.apm.plugin.spring.mvc.commons.EnhanceRequireObjectCache; + +import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.FORWARD_REQUEST_FLAG; +import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.WEBFLUX_REQUEST_KEY; + +/** + * the abstract method inteceptor + */ +public abstract class AbstractMethodInterceptor implements InstanceMethodsAroundInterceptor { + public abstract String getRequestURL(Method method); + + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, + MethodInterceptResult result) throws Throwable { + + Boolean forwardRequestFlag = (Boolean)ContextManager.getRuntimeContext().get(FORWARD_REQUEST_FLAG); + /** + * Spring MVC plugin do nothing if current request is forward request. + * Ref: https://github.com/apache/incubator-skywalking/pull/1325 + */ + if (forwardRequestFlag != null && forwardRequestFlag) { + return; + } + + EnhanceRequireObjectCache pathMappingCache = (EnhanceRequireObjectCache)objInst.getSkyWalkingDynamicField(); + String requestURL = pathMappingCache.findPathMapping(method); + if (requestURL == null) { + requestURL = getRequestURL(method); + pathMappingCache.addPathMapping(method, requestURL); + requestURL = pathMappingCache.findPathMapping(method); + } + + HttpRequest request = (HttpRequest)ContextManager.getRuntimeContext().get(WEBFLUX_REQUEST_KEY); + if (request != null) { + ContextCarrier contextCarrier = new ContextCarrier(); + CarrierItem next = contextCarrier.items(); + while (next.hasNext()) { + next = next.next(); + next.setHeadValue(request.headers().get(next.getHeadKey())); + } + + AbstractSpan span = ContextManager.createEntrySpan(requestURL, contextCarrier); + Tags.URL.set(span, request.uri().toString()); + Tags.HTTP.METHOD.set(span, request.method().name()); + span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION); + SpanLayer.asHttp(span); + } + } + + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, + Object ret) throws Throwable { + Boolean forwardRequestFlag = (Boolean)ContextManager.getRuntimeContext().get(FORWARD_REQUEST_FLAG); + /** + * Spring MVC plugin do nothing if current request is forward request. + * Ref: https://github.com/apache/incubator-skywalking/pull/1325 + */ + if (forwardRequestFlag != null && forwardRequestFlag) { + return ret; + } + + ContextManager.stopSpan(); + return ret; + } + + @Override + public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class<?>[] argumentsTypes, Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/ConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/ConstructorInterceptor.java new file mode 100644 index 0000000000..d8a5566d49 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/ConstructorInterceptor.java @@ -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. + */ + +package org.apache.skywalking.apm.plugin.spring.webflux.v5; + +import io.netty.handler.codec.http.HttpRequest; +import org.apache.skywalking.apm.agent.core.context.ContextManager; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; + +import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.WEBFLUX_REQUEST_KEY; + +public class ConstructorInterceptor implements InstanceConstructorInterceptor { + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + HttpRequest httpRequest = (HttpRequest)allArguments[3]; + ContextManager.getRuntimeContext().put(WEBFLUX_REQUEST_KEY, httpRequest); + } +} \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/ConstructorWithHttpRequestInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/ConstructorWithHttpRequestInterceptor.java new file mode 100644 index 0000000000..e568f9fb8f --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/ConstructorWithHttpRequestInterceptor.java @@ -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. + */ + +package org.apache.skywalking.apm.plugin.spring.webflux.v5; + +import io.netty.handler.codec.http.HttpRequest; +import org.apache.skywalking.apm.agent.core.context.ContextManager; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; + +import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.WEBFLUX_REQUEST_KEY; + +public class ConstructorWithHttpRequestInterceptor implements InstanceConstructorInterceptor { + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + HttpRequest httpRequest = (HttpRequest)allArguments[4]; + ContextManager.getRuntimeContext().put(WEBFLUX_REQUEST_KEY, httpRequest); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/ControllerConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/ControllerConstructorInterceptor.java new file mode 100644 index 0000000000..947cd794fc --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/ControllerConstructorInterceptor.java @@ -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.webflux.v5; + +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.mvc.commons.EnhanceRequireObjectCache; +import org.apache.skywalking.apm.plugin.spring.mvc.commons.PathMappingCache; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * The <code>ControllerConstructorInterceptor</code> intercepts the Controller's constructor, in order to acquire the + * mapping annotation, if exist. + * + * But, you can see we only use the first mapping value, <B>Why?</B> + * + * Right now, we intercept the controller by annotation as you known, so we CAN'T know which uri patten is actually + * matched. Even we know, that costs a lot. + * + * If we want to resolve that, we must intercept the Spring MVC core codes, that is not a good choice for now. + * + * Comment by @wu-sheng + */ +public class ControllerConstructorInterceptor implements InstanceConstructorInterceptor { + + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + String basePath = ""; + RequestMapping basePathRequestMapping = objInst.getClass().getAnnotation(RequestMapping.class); + if (basePathRequestMapping != null) { + if (basePathRequestMapping.value().length > 0) { + basePath = basePathRequestMapping.value()[0]; + } else if (basePathRequestMapping.path().length > 0) { + basePath = basePathRequestMapping.path()[0]; + } + } + EnhanceRequireObjectCache enhanceRequireObjectCache = new EnhanceRequireObjectCache(); + enhanceRequireObjectCache.setPathMappingCache(new PathMappingCache(basePath)); + objInst.setSkyWalkingDynamicField(enhanceRequireObjectCache); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/OnInboundNextInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/OnInboundNextInterceptor.java new file mode 100644 index 0000000000..d439ce137b --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/OnInboundNextInterceptor.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.skywalking.apm.plugin.spring.webflux.v5; + +import io.netty.handler.codec.http.HttpRequest; +import java.lang.reflect.Method; +import org.apache.skywalking.apm.agent.core.context.CarrierItem; +import org.apache.skywalking.apm.agent.core.context.ContextCarrier; +import org.apache.skywalking.apm.agent.core.context.ContextManager; +import org.apache.skywalking.apm.agent.core.context.tag.Tags; +import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; +import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; + +import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.WEBFLUX_REQUEST_KEY; + +public class OnInboundNextInterceptor implements InstanceMethodsAroundInterceptor { + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, + MethodInterceptResult result) throws Throwable { + HttpRequest request = (HttpRequest)ContextManager.getRuntimeContext().get(WEBFLUX_REQUEST_KEY); + if (request != null) { + ContextCarrier contextCarrier = new ContextCarrier(); + CarrierItem next = contextCarrier.items(); + while (next.hasNext()) { + next = next.next(); + next.setHeadValue(request.headers().get(next.getHeadKey())); + } + + AbstractSpan span = ContextManager.createEntrySpan(request.uri(), contextCarrier); + Tags.URL.set(span, request.uri()); + Tags.HTTP.METHOD.set(span, request.method().name()); + span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION); + SpanLayer.asHttp(span); + } + } + + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, + Object ret) throws Throwable { + return ret; + } + + @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class<?>[] argumentsTypes, Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/OnOutboundCompleteInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/OnOutboundCompleteInterceptor.java new file mode 100644 index 0000000000..8e45035ff8 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/OnOutboundCompleteInterceptor.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.plugin.spring.webflux.v5; + +import io.netty.handler.codec.http.HttpRequest; +import java.lang.reflect.Method; +import org.apache.skywalking.apm.agent.core.context.ContextManager; +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 static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.WEBFLUX_REQUEST_KEY; + +public class OnOutboundCompleteInterceptor 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 { + HttpRequest request = (HttpRequest)ContextManager.getRuntimeContext().get(WEBFLUX_REQUEST_KEY); + if (request != null) { + ContextManager.stopSpan(); + ContextManager.getRuntimeContext().remove(WEBFLUX_REQUEST_KEY); + } + return ret; + } + + @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class<?>[] argumentsTypes, Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/OnOutboundErrorInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/OnOutboundErrorInterceptor.java new file mode 100644 index 0000000000..496b57e197 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/OnOutboundErrorInterceptor.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.skywalking.apm.plugin.spring.webflux.v5; + +import io.netty.handler.codec.http.HttpRequest; +import java.lang.reflect.Method; +import org.apache.skywalking.apm.agent.core.context.ContextManager; +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 static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.WEBFLUX_REQUEST_KEY; + +public class OnOutboundErrorInterceptor implements InstanceMethodsAroundInterceptor { + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, + MethodInterceptResult result) throws Throwable { + Throwable exception = (Throwable)allArguments[0]; + HttpRequest request = (HttpRequest)ContextManager.getRuntimeContext().get(WEBFLUX_REQUEST_KEY); + if (request != null) { + ContextManager.activeSpan().errorOccurred().log(exception); + } + + } + + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, + Object ret) throws Throwable { + return ret; + } + + @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class<?>[] argumentsTypes, Throwable t) { + + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/RequestMappingMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/RequestMappingMethodInterceptor.java new file mode 100644 index 0000000000..3bace06cec --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/RequestMappingMethodInterceptor.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.skywalking.apm.plugin.spring.webflux.v5; + +import java.lang.reflect.Method; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * The <code>RequestMappingMethodInterceptor</code> only use the first mapping value. it will inteceptor with + * <code>@RequestMapping</code> + * + * @author clevertension + */ +public class RequestMappingMethodInterceptor extends AbstractMethodInterceptor { + @Override + public String getRequestURL(Method method) { + String requestURL = ""; + RequestMapping methodRequestMapping = method.getAnnotation(RequestMapping.class); + if (methodRequestMapping.value().length > 0) { + requestURL = methodRequestMapping.value()[0]; + } else if (methodRequestMapping.path().length > 0) { + requestURL = methodRequestMapping.path()[0]; + } + return requestURL; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/RestMappingMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/RestMappingMethodInterceptor.java new file mode 100644 index 0000000000..064671c272 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/RestMappingMethodInterceptor.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.skywalking.apm.plugin.spring.webflux.v5; + +import java.lang.reflect.Method; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; + +/** + * The <code>RestMappingMethodInterceptor</code> only use the first mapping value. it will inteceptor with + * <code>@GetMapping</code>, <code>@PostMapping</code>, <code>@PutMapping</code> + * <code>@DeleteMapping</code>, <code>@PatchMapping</code> + * + * @author clevertension + */ +public class RestMappingMethodInterceptor extends AbstractMethodInterceptor { + @Override + public String getRequestURL(Method method) { + String requestURL = ""; + GetMapping getMapping = method.getAnnotation(GetMapping.class); + PostMapping postMapping = method.getAnnotation(PostMapping.class); + PutMapping putMapping = method.getAnnotation(PutMapping.class); + DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class); + PatchMapping patchMapping = method.getAnnotation(PatchMapping.class); + if (getMapping != null) { + if (getMapping.value().length > 0) { + requestURL = getMapping.value()[0]; + } else if (getMapping.path().length > 0) { + requestURL = getMapping.path()[0]; + } + } else if (postMapping != null) { + if (postMapping.value().length > 0) { + requestURL = postMapping.value()[0]; + } else if (postMapping.path().length > 0) { + requestURL = postMapping.path()[0]; + } + } else if (putMapping != null) { + if (putMapping.value().length > 0) { + requestURL = putMapping.value()[0]; + } else if (putMapping.path().length > 0) { + requestURL = putMapping.path()[0]; + } + } else if (deleteMapping != null) { + if (deleteMapping.value().length > 0) { + requestURL = deleteMapping.value()[0]; + } else if (deleteMapping.path().length > 0) { + requestURL = deleteMapping.path()[0]; + } + } else if (patchMapping != null) { + if (patchMapping.value().length > 0) { + requestURL = patchMapping.value()[0]; + } else if (patchMapping.path().length > 0) { + requestURL = patchMapping.path()[0]; + } + } + return requestURL; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/StatusInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/StatusInterceptor.java new file mode 100644 index 0000000000..e2717657af --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/StatusInterceptor.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.plugin.spring.webflux.v5; + +import io.netty.handler.codec.http.HttpResponseStatus; +import java.lang.reflect.Method; +import org.apache.skywalking.apm.agent.core.context.ContextManager; +import org.apache.skywalking.apm.agent.core.context.tag.Tags; +import org.apache.skywalking.apm.agent.core.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; + +public class StatusInterceptor implements InstanceMethodsAroundInterceptor { + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, + MethodInterceptResult result) throws Throwable { + HttpResponseStatus status = (HttpResponseStatus)allArguments[0]; + if (status.code() > 400) { + ContextManager.activeSpan().errorOccurred(); + Tags.STATUS_CODE.set(ContextManager.activeSpan(), String.valueOf(status.code())); + } + } + + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, + Object ret) throws Throwable { + return ret; + } + + @Override + public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class<?>[] argumentsTypes, Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/AbstractControllerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/AbstractControllerInstrumentation.java new file mode 100644 index 0000000000..2d415731be --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/AbstractControllerInstrumentation.java @@ -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.webflux.v5.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.DeclaredInstanceMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch; +import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; + +import static net.bytebuddy.matcher.ElementMatchers.any; +import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; +import static net.bytebuddy.matcher.ElementMatchers.named; + +/** + * {@link ControllerInstrumentation} enhance all constructor and method annotated with + * <code>org.springframework.web.bind.annotation.RequestMapping</code> that class has + * <code>org.springframework.stereotype.Controller</code> annotation. + * + * <code>ControllerConstructorInterceptor</code> set the controller base path to + * dynamic field before execute constructor. + * + * <code>org.apache.skywalking.apm.plugin.spring.mvc.v4.RequestMappingMethodInterceptor</code> get the request path + * from dynamic field first, if not found, <code>RequestMappingMethodInterceptor</code> generate request path that + * combine the path value of current annotation on current method and the base path and set the new path to the dynamic + * filed + * + * @author zhangxin + */ +public abstract class AbstractControllerInstrumentation extends AbstractSpringWebflux5Instrumentation { + @Override + protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[] { + new ConstructorInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getConstructorMatcher() { + return any(); + } + + @Override + public String getConstructorInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.webflux.v5.ControllerConstructorInterceptor"; + } + } + }; + } + + @Override + protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new DeclaredInstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return isAnnotatedWith(named("org.springframework.web.bind.annotation.RequestMapping")); + } + + @Override + public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.webflux.v5.RequestMappingMethodInterceptor"; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + }, + new DeclaredInstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return isAnnotatedWith(named("org.springframework.web.bind.annotation.GetMapping")) + .or(isAnnotatedWith(named("org.springframework.web.bind.annotation.PostMapping"))) + .or(isAnnotatedWith(named("org.springframework.web.bind.annotation.PutMapping"))) + .or(isAnnotatedWith(named("org.springframework.web.bind.annotation.DeleteMapping"))) + .or(isAnnotatedWith(named("org.springframework.web.bind.annotation.PatchMapping"))); + } + + @Override + public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.webflux.v5.RestMappingMethodInterceptor"; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override + protected ClassMatch enhanceClass() { + return ClassAnnotationMatch.byClassAnnotationMatch(getEnhanceAnnotations()); + } + + protected abstract String[] getEnhanceAnnotations(); + +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/AbstractSpringWebflux5Instrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/AbstractSpringWebflux5Instrumentation.java new file mode 100644 index 0000000000..7559e729b9 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/AbstractSpringWebflux5Instrumentation.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.skywalking.apm.plugin.spring.webflux.v5.define; + +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; + +public abstract class AbstractSpringWebflux5Instrumentation extends ClassInstanceMethodsEnhancePluginDefine { + public static final String WITHNESS_CLASSES = "org.springframework.web.reactive.BindingContext"; + + @Override + protected final String[] witnessClasses() { + return new String[] {WITHNESS_CLASSES}; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/ControllerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/ControllerInstrumentation.java new file mode 100644 index 0000000000..d977064e73 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/ControllerInstrumentation.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.skywalking.apm.plugin.spring.webflux.v5.define; + +public class ControllerInstrumentation extends AbstractControllerInstrumentation { + + public static final String ENHANCE_ANNOTATION = "org.springframework.stereotype.Controller"; + + @Override protected String[] getEnhanceAnnotations() { + return new String[] {ENHANCE_ANNOTATION}; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/HttpServerOperations20xInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/HttpServerOperations20xInstrumentation.java new file mode 100644 index 0000000000..bd26e37e5f --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/HttpServerOperations20xInstrumentation.java @@ -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.webflux.v5.define; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; +import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; +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 HttpServerOperations20xInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + @Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[] { + new ConstructorInterceptPoint() { + @Override public ElementMatcher<MethodDescription> getConstructorMatcher() { + return takesArgumentWithType(4, "io.netty.handler.codec.http.HttpRequest"); + } + + @Override public String getConstructorInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.webflux.v5.ConstructorWithHttpRequestInterceptor"; + } + } + }; + } + + @Override protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new InstanceMethodsInterceptPoint() { + @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("status").and(takesArguments(1)); + } + + @Override public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.webflux.v5.StatusInterceptor"; + } + + @Override public boolean isOverrideArgs() { + return false; + } + }, + new InstanceMethodsInterceptPoint() { + @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("onInboundNext"); + } + + @Override public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.webflux.v5.OnInboundNextInterceptor"; + } + + @Override public boolean isOverrideArgs() { + return false; + } + }, + new InstanceMethodsInterceptPoint() { + @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("onOutboundComplete"); + } + + @Override public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.webflux.v5.OnOutboundCompleteInterceptor"; + } + + @Override public boolean isOverrideArgs() { + return false; + } + }, + new InstanceMethodsInterceptPoint() { + @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("onOutboundError"); + } + + @Override public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.webflux.v5.OnOutboundErrorInterceptor"; + } + + @Override public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override protected ClassMatch enhanceClass() { + return byName("reactor.ipc.netty.http.server.HttpServerOperations"); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/HttpServerOperations21xInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/HttpServerOperations21xInstrumentation.java new file mode 100644 index 0000000000..3d19bbe93c --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/HttpServerOperations21xInstrumentation.java @@ -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.webflux.v5.define; + +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine; +import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; +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 HttpServerOperations21xInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + @Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[] { + new ConstructorInterceptPoint() { + @Override public ElementMatcher<MethodDescription> getConstructorMatcher() { + return takesArgumentWithType(3, "io.netty.handler.codec.http.HttpRequest"); + } + + @Override public String getConstructorInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.webflux.v5.ConstructorInterceptor"; + } + } + }; + } + + @Override protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new InstanceMethodsInterceptPoint() { + @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("status").and(takesArguments(1)); + } + + @Override public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.webflux.v5.StatusInterceptor"; + } + + @Override public boolean isOverrideArgs() { + return false; + } + }, + new InstanceMethodsInterceptPoint() { + @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("onInboundNext"); + } + + @Override public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.webflux.v5.OnInboundNextInterceptor"; + } + + @Override public boolean isOverrideArgs() { + return false; + } + }, + new InstanceMethodsInterceptPoint() { + @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("onOutboundComplete"); + } + + @Override public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.webflux.v5.OnOutboundCompleteInterceptor"; + } + + @Override public boolean isOverrideArgs() { + return false; + } + }, + new InstanceMethodsInterceptPoint() { + @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("onOutboundError"); + } + + @Override public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.spring.webflux.v5.OnOutboundErrorInterceptor"; + } + + @Override public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override protected ClassMatch enhanceClass() { + return byName("reactor.netty.http.server.HttpServerOperations"); + } +} \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/RestControllerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/RestControllerInstrumentation.java new file mode 100644 index 0000000000..fb405b0642 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/define/RestControllerInstrumentation.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.skywalking.apm.plugin.spring.webflux.v5.define; + +public class RestControllerInstrumentation extends AbstractControllerInstrumentation { + + public static final String ENHANCE_ANNOTATION = "org.springframework.web.bind.annotation.RestController"; + + @Override protected String[] getEnhanceAnnotations() { + return new String[] {ENHANCE_ANNOTATION}; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/resources/skywalking-plugin.def new file mode 100644 index 0000000000..54affbeabf --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/webflux-5.x-plugin/src/main/resources/skywalking-plugin.def @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +spring-webflux-5.x=org.apache.skywalking.apm.plugin.spring.webflux.v5.define.HttpServerOperations20xInstrumentation +spring-webflux-5.x=org.apache.skywalking.apm.plugin.spring.webflux.v5.define.HttpServerOperations21xInstrumentation +spring-webflux-5.x=org.apache.skywalking.apm.plugin.spring.webflux.v5.define.ControllerInstrumentation +spring-webflux-5.x=org.apache.skywalking.apm.plugin.spring.webflux.v5.define.RestControllerInstrumentation diff --git a/docs/en/setup/service-agent/java-agent/Supported-list.md b/docs/en/setup/service-agent/java-agent/Supported-list.md index 7573ae72f9..ac836b0350 100644 --- a/docs/en/setup/service-agent/java-agent/Supported-list.md +++ b/docs/en/setup/service-agent/java-agent/Supported-list.md @@ -3,12 +3,13 @@ * [Tomcat](https://github.com/apache/tomcat) 8 * [Tomcat](https://github.com/apache/tomcat) 9 * [Spring Boot](https://github.com/spring-projects/spring-boot) Web 4.x - * Spring MVC 3.x, 4.x with servlet 3.x + * Spring MVC 3.x, 4.x 5.x with servlet 3.x * [Nutz Web Framework](https://github.com/nutzam/nutz) 1.x * [Struts2 MVC](http://struts.apache.org/) 2.3.x -> 2.5.x * [Resin](http://www.caucho.com/resin-4.0/) 3 (Optional¹) * [Resin](http://www.caucho.com/resin-4.0/) 4 (Optional¹) * [Jetty Server](http://www.eclipse.org/jetty/) 9 + * [Spring Webflux](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html) 5.x * [Undertow](http://undertow.io/) 2.0.0.Final -> 2.0.13.Final * HTTP Client * [Feign](https://github.com/OpenFeign/feign) 9.x ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services