diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/ExecuteRootHandlerInterceptor.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/ExecuteRootHandlerInterceptor.java deleted file mode 100644 index 6afb43c04..000000000 --- a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/ExecuteRootHandlerInterceptor.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.undertow.v2x; - -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.MethodInterceptResult; -import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor; -import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; - -import java.lang.reflect.Method; - -import io.undertow.server.HttpServerExchange; -import io.undertow.util.HeaderMap; - -/** - * @author chenpengfei - */ -public class ExecuteRootHandlerInterceptor implements StaticMethodsAroundInterceptor { - - @Override - public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, MethodInterceptResult result) { - HttpServerExchange exchange = (HttpServerExchange) allArguments[1]; - - ContextCarrier contextCarrier = new ContextCarrier(); - HeaderMap headers = exchange.getRequestHeaders(); - CarrierItem next = contextCarrier.items(); - while (next.hasNext()) { - next = next.next(); - next.setHeadValue(headers.getFirst(next.getHeadKey())); - } - AbstractSpan span = ContextManager.createEntrySpan(exchange.getRequestPath(), contextCarrier); - Tags.URL.set(span, exchange.getRequestURL()); - Tags.HTTP.METHOD.set(span, exchange.getRequestMethod().toString()); - span.setComponent(ComponentsDefine.UNDERTOW); - SpanLayer.asHttp(span); - } - - @Override - public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, Object ret) { - HttpServerExchange exchange = (HttpServerExchange) allArguments[1]; - - AbstractSpan span = ContextManager.activeSpan(); - if (exchange.getStatusCode() >= 400) { - span.errorOccurred(); - Tags.STATUS_CODE.set(span, Integer.toString(exchange.getStatusCode())); - } - ContextManager.stopSpan(); - ContextManager.getRuntimeContext().remove(Constants.FORWARD_REQUEST_FLAG); - return ret; - } - - @Override - public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class[] parameterTypes, Throwable t) { - ContextManager.activeSpan().errorOccurred().log(t); - } -} diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/ListenerConfigInterceptor.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/ListenerConfigInterceptor.java new file mode 100644 index 000000000..048c188a9 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/ListenerConfigInterceptor.java @@ -0,0 +1,60 @@ +/* + * 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.undertow.v2x; + +import io.undertow.Undertow; +import io.undertow.server.HttpHandler; +import io.undertow.server.RoutingHandler; +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.apache.skywalking.apm.plugin.undertow.v2x.handler.TracingHandler; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * @author AI + * 2019-08-10 + */ +public class ListenerConfigInterceptor implements InstanceMethodsAroundInterceptor { + + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, MethodInterceptResult result) throws Throwable { + final Undertow.ListenerBuilder builder = (Undertow.ListenerBuilder) allArguments[0]; + final Field rootHandlerField = Undertow.ListenerBuilder.class.getDeclaredField("rootHandler"); + rootHandlerField.setAccessible(true); + final Object handler = rootHandlerField.get(builder); + if (null != handler && !(handler instanceof RoutingHandler)) { + rootHandlerField.set(builder, new TracingHandler((HttpHandler) handler)); + } + } + + @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/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/RootHandlerInterceptor.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/RootHandlerInterceptor.java new file mode 100644 index 000000000..78b3839ec --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/RootHandlerInterceptor.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.apache.skywalking.apm.plugin.undertow.v2x; + +import io.undertow.server.HttpHandler; +import io.undertow.server.RoutingHandler; +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.apache.skywalking.apm.plugin.undertow.v2x.handler.TracingHandler; + +import java.lang.reflect.Method; + +/** + * @author chenpengfei + * @author AI + */ +public class RootHandlerInterceptor implements InstanceMethodsAroundInterceptor { + + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, MethodInterceptResult result) throws Throwable { + int handlerIndex = allArguments.length - 1; + if (!(allArguments[handlerIndex] instanceof RoutingHandler)) { + allArguments[handlerIndex] = new TracingHandler((HttpHandler) allArguments[handlerIndex]); + } + } + + @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/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/RoutingHandlerInterceptor.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/RoutingHandlerInterceptor.java new file mode 100644 index 000000000..3a5c86675 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/RoutingHandlerInterceptor.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.plugin.undertow.v2x; + +import io.undertow.server.HttpHandler; +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.apache.skywalking.apm.plugin.undertow.v2x.handler.TracingHandler; + +import java.lang.reflect.Method; + +/** + * @author AI + * 2019-07-25 + */ +public class RoutingHandlerInterceptor implements InstanceMethodsAroundInterceptor { + + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, MethodInterceptResult result) throws Throwable { + final int httpHandlerIndex = argumentsTypes.length - 1; + final HttpHandler handler = (HttpHandler) allArguments[httpHandlerIndex]; + final String template = (String) allArguments[1]; + allArguments[httpHandlerIndex] = new TracingHandler(template, handler); + } + + @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/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/RoutingHandlerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/RoutingHandlerInstrumentation.java new file mode 100644 index 000000000..1e9361c9e --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/RoutingHandlerInstrumentation.java @@ -0,0 +1,83 @@ +/* + * 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.undertow.v2x.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 org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType; +import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName; + + +/** + * @author AI + * 2019-07-26 + */ +public class RoutingHandlerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + private static final String ENHANCE_METHOD = "add"; + private static final String ENHANCE_CLASS = "io.undertow.server.RoutingHandler"; + private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.undertow.v2x.RoutingHandlerInterceptor"; + + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[0]; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return RoutingHandlerInstrumentation.getRoutingHandlerMethodMatcher(); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPTOR_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return true; + } + } + }; + } + + @Override + protected ClassMatch enhanceClass() { + return byName(ENHANCE_CLASS); + } + + public static ElementMatcher getRoutingHandlerMethodMatcher() { + final ElementMatcher.Junction basicMatcher = named(ENHANCE_METHOD) + .and(takesArgumentWithType(0, "io.undertow.util.HttpString")) + .and(takesArgumentWithType(1, "java.lang.String")); + final String httpHandlerClassName = "io.undertow.server.HttpHandler"; + return (basicMatcher.and(takesArgumentWithType(2, httpHandlerClassName))) + .or(basicMatcher.and(takesArgumentWithType(3, httpHandlerClassName))); + } + +} diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/UndertowAddListenerInstrumentation.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/UndertowAddListenerInstrumentation.java new file mode 100644 index 000000000..75445d176 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/UndertowAddListenerInstrumentation.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.plugin.undertow.v2x.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 org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType; +import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName; + + +/** + * @author AI + * 2019-08-10 + */ +public class UndertowAddListenerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + private static final String ENHANCE_CLASS = "io.undertow.Undertow$Builder"; + private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.undertow.v2x.RootHandlerInterceptor"; + private static final String[] ENHANCE_METHODS = new String[]{"addHttpListener", "addHttpsListener", "addAjpListener"}; + + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[0]; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + final InstanceMethodsInterceptPoint[] points = new InstanceMethodsInterceptPoint[ENHANCE_METHODS.length]; + for (int i = 0; i < ENHANCE_METHODS.length; i++) { + final String method = ENHANCE_METHODS[i]; + final InstanceMethodsInterceptPoint point = new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return named(method).and(takesArgumentWithType(2, "io.undertow.server.HttpHandler")); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPTOR_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return true; + } + }; + points[i] = point; + } + return points; + } + + @Override + protected ClassMatch enhanceClass() { + return byName(ENHANCE_CLASS); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/UndertowListenerConfigInstrumentation.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/UndertowListenerConfigInstrumentation.java new file mode 100644 index 000000000..f7e36dfd9 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/UndertowListenerConfigInstrumentation.java @@ -0,0 +1,78 @@ +/* + * 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.undertow.v2x.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 org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType; +import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName; + +/** + * @author AI + * 2019-08-10 + */ +public class UndertowListenerConfigInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + private static final String ENHANCE_METHOD = "addListener"; + private static final String ENHANCE_CLASS = "io.undertow.Undertow$Builder"; + private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.undertow.v2x.ListenerConfigInterceptor"; + + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[0]; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return UndertowListenerConfigInstrumentation.getUndertowBuilderMethodMatcher(); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPTOR_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override + protected ClassMatch enhanceClass() { + return byName(ENHANCE_CLASS); + } + + public static ElementMatcher getUndertowBuilderMethodMatcher() { + return named(ENHANCE_METHOD).and(takesArgumentWithType(0, "io.undertow.Undertow$ListenerBuilder")); + } + +} diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/UndertowInstrumentation.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/UndertowRootHandlerInstrumentation.java similarity index 55% rename from apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/UndertowInstrumentation.java rename to apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/UndertowRootHandlerInstrumentation.java index b88a0586f..7c606db30 100644 --- a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/UndertowInstrumentation.java +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/UndertowRootHandlerInstrumentation.java @@ -20,35 +20,38 @@ package org.apache.skywalking.apm.plugin.undertow.v2x.define; 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.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 org.apache.skywalking.apm.agent.core.plugin.match.NameMatch; import static net.bytebuddy.matcher.ElementMatchers.named; +import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType; +import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName; /** * @author chenpengfei + * @author AI */ -public class UndertowInstrumentation extends ClassStaticMethodsEnhancePluginDefine { +public class UndertowRootHandlerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { - private static final String ENHANCE_CLASS = "io.undertow.server.Connectors"; - private static final String ENHANCE_METHOD = "executeRootHandler"; - private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.undertow.v2x.ExecuteRootHandlerInterceptor"; + private static final String ENHANCE_METHOD = "setHandler"; + private static final String ENHANCE_CLASS = "io.undertow.Undertow$Builder"; + private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.undertow.v2x.RootHandlerInterceptor"; @Override - protected ClassMatch enhanceClass() { - return NameMatch.byName(ENHANCE_CLASS); + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[0]; } @Override - public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() { - return new StaticMethodsInterceptPoint[] { - new StaticMethodsInterceptPoint() { + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { @Override public ElementMatcher getMethodsMatcher() { - return named(ENHANCE_METHOD); + return named(ENHANCE_METHOD).and(takesArgumentWithType(0, "io.undertow.server.HttpHandler")); } @Override @@ -56,10 +59,17 @@ public class UndertowInstrumentation extends ClassStaticMethodsEnhancePluginDefi return INTERCEPTOR_CLASS; } - @Override public boolean isOverrideArgs() { - return false; + @Override + public boolean isOverrideArgs() { + return true; } } }; } + + @Override + protected ClassMatch enhanceClass() { + return byName(ENHANCE_CLASS); + } + } diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/handler/TracingHandler.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/handler/TracingHandler.java new file mode 100644 index 000000000..a8ceb2f46 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/handler/TracingHandler.java @@ -0,0 +1,97 @@ +/* + * 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.undertow.v2x.handler; + +import io.undertow.server.ExchangeCompletionListener; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HeaderMap; +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.network.trace.component.ComponentsDefine; +import org.apache.skywalking.apm.plugin.undertow.v2x.Constants; + +/** + * @author AI + * 2019-08-06 + */ +public class TracingHandler implements HttpHandler { + private final String template; + private final HttpHandler next; + + public TracingHandler(HttpHandler handler) { + this(null, handler); + } + + + public TracingHandler(String template, HttpHandler handler) { + this.next = handler; + this.template = template; + } + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + final HeaderMap headers = exchange.getRequestHeaders(); + final ContextCarrier carrier = new ContextCarrier(); + CarrierItem items = carrier.items(); + while (items.hasNext()) { + items = items.next(); + items.setHeadValue(headers.getFirst(items.getHeadKey())); + } + String operationName; + if (null == template) { + operationName = exchange.getRequestPath(); + } else { + operationName = template; + } + final AbstractSpan span = ContextManager.createEntrySpan(operationName, carrier); + Tags.URL.set(span, exchange.getRequestURL()); + Tags.HTTP.METHOD.set(span, exchange.getRequestMethod().toString()); + span.setComponent(ComponentsDefine.UNDERTOW); + SpanLayer.asHttp(span); + try { + span.prepareForAsync(); + exchange.addExchangeCompleteListener(new ExchangeCompletionListener() { + @Override + public void exchangeEvent(HttpServerExchange httpServerExchange, NextListener nextListener) { + nextListener.proceed(); + if (httpServerExchange.getStatusCode() >= 400) { + span.errorOccurred(); + Tags.STATUS_CODE.set(span, Integer.toString(httpServerExchange.getStatusCode())); + } + span.asyncFinish(); + } + }); + } catch (Throwable e) { + ContextManager.activeSpan().log(e); + } + try { + next.handleRequest(exchange); + } catch (Throwable e) { + span.errorOccurred().log(e); + } finally { + ContextManager.stopSpan(span); + ContextManager.getRuntimeContext().remove(Constants.FORWARD_REQUEST_FLAG); + } + } + +} diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/resources/skywalking-plugin.def index a6070c618..315079b47 100644 --- a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/resources/skywalking-plugin.def +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/resources/skywalking-plugin.def @@ -14,5 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +undertow-2.x-plugin=org.apache.skywalking.apm.plugin.undertow.v2x.define.RoutingHandlerInstrumentation undertow-2.x-plugin=org.apache.skywalking.apm.plugin.undertow.v2x.define.RequestDispatcherImplInstrumentation -undertow-2.x-plugin=org.apache.skywalking.apm.plugin.undertow.v2x.define.UndertowInstrumentation \ No newline at end of file +undertow-2.x-plugin=org.apache.skywalking.apm.plugin.undertow.v2x.define.UndertowRootHandlerInstrumentation +undertow-2.x-plugin=org.apache.skywalking.apm.plugin.undertow.v2x.define.UndertowAddListenerInstrumentation +undertow-2.x-plugin=org.apache.skywalking.apm.plugin.undertow.v2x.define.UndertowListenerConfigInstrumentation diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/RootHandlerInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/RootHandlerInterceptorTest.java new file mode 100644 index 000000000..6ce11dbf8 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/RootHandlerInterceptorTest.java @@ -0,0 +1,104 @@ +/* + * 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.undertow.v2x; + +import io.undertow.Undertow; +import io.undertow.server.HttpHandler; +import io.undertow.server.RoutingHandler; +import io.undertow.util.Methods; +import org.apache.skywalking.apm.agent.core.conf.Config; +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.test.tools.AgentServiceRule; +import org.apache.skywalking.apm.agent.test.tools.SegmentStorage; +import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint; +import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner; +import org.apache.skywalking.apm.plugin.undertow.v2x.handler.TracingHandler; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.modules.junit4.PowerMockRunnerDelegate; + +import java.lang.reflect.Method; + +import static org.junit.Assert.assertTrue; + +/** + * @author chenpengfei + */ +@RunWith(PowerMockRunner.class) +@PowerMockRunnerDelegate(TracingSegmentRunner.class) +public class RootHandlerInterceptorTest { + + private RootHandlerInterceptor rootHandlerInterceptor; + + @SegmentStoragePoint + private SegmentStorage segmentStorage; + + @Rule + public AgentServiceRule serviceRule = new AgentServiceRule(); + + @Mock + private HttpHandler httpHandler; + + + @Mock + private MethodInterceptResult methodInterceptResult; + + @Mock + private EnhancedInstance enhancedInstance; + + + @Before + public void setUp() throws Exception { + Config.Agent.ACTIVE_V1_HEADER = true; + rootHandlerInterceptor = new RootHandlerInterceptor(); + } + + @After + public void clear() { + Config.Agent.ACTIVE_V1_HEADER = false; + } + + @Test + public void testBindTracingHandler() throws Throwable { + Object[] arguments = new Object[]{httpHandler}; + Class[] argumentType = new Class[]{HttpHandler.class}; + final Method method = Undertow.Builder.class.getMethod("setHandler", argumentType); + rootHandlerInterceptor.beforeMethod(enhancedInstance, method, arguments, argumentType, methodInterceptResult); + rootHandlerInterceptor.afterMethod(enhancedInstance, method, arguments, argumentType, null); + assertTrue(arguments[0] instanceof TracingHandler); + } + + @Test + public void testBindRoutingHandler() throws Throwable { + RoutingHandler handler = new RoutingHandler(); + handler.add(Methods.GET, "/projects/{projectId}", httpHandler); + Object[] arguments = new Object[]{handler}; + Class[] argumentType = new Class[]{HttpHandler.class}; + final Method method = Undertow.Builder.class.getMethod("setHandler", argumentType); + rootHandlerInterceptor.beforeMethod(enhancedInstance, method, arguments, argumentType, methodInterceptResult); + rootHandlerInterceptor.afterMethod(enhancedInstance, method, arguments, argumentType, null); + assertTrue(arguments[0] instanceof RoutingHandler); + } +} \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/RoutingHandlerInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/RoutingHandlerInterceptorTest.java new file mode 100644 index 000000000..f63da22dc --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/RoutingHandlerInterceptorTest.java @@ -0,0 +1,144 @@ +/* + * 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.undertow.v2x; + +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.RoutingHandler; +import io.undertow.server.ServerConnection; +import io.undertow.util.HeaderMap; +import io.undertow.util.HttpString; +import io.undertow.util.Methods; +import io.undertow.util.StatusCodes; +import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan; +import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer; +import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import org.apache.skywalking.apm.agent.test.helper.SegmentHelper; +import org.apache.skywalking.apm.agent.test.helper.SpanHelper; +import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule; +import org.apache.skywalking.apm.agent.test.tools.SegmentStorage; +import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint; +import org.apache.skywalking.apm.agent.test.tools.SpanAssert; +import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner; +import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; +import org.apache.skywalking.apm.plugin.undertow.v2x.handler.TracingHandler; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.modules.junit4.PowerMockRunnerDelegate; + +import java.lang.reflect.Method; +import java.net.InetSocketAddress; +import java.util.List; + +import static org.apache.skywalking.apm.agent.test.tools.SpanAssert.assertComponent; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; + +/** + * @author AI + * 2019-07-29 + */ +@RunWith(PowerMockRunner.class) +@PowerMockRunnerDelegate(TracingSegmentRunner.class) +public class RoutingHandlerInterceptorTest { + private RoutingHandlerInterceptor interceptor; + @SegmentStoragePoint + private SegmentStorage segmentStorage; + @Rule + public AgentServiceRule serviceRule = new AgentServiceRule(); + @Mock + private HttpHandler httpHandler; + @Mock + ServerConnection serverConnection; + + @Mock + private MethodInterceptResult methodInterceptResult; + @Mock + private EnhancedInstance enhancedInstance; + private String template = "/projects/{projectId}/users"; + private String uri = "/projects/{projectId}/users"; + + @Before + public void setUp() throws Exception { + interceptor = new RoutingHandlerInterceptor(); + + } + + @Test + public void testBindArguments() throws Throwable { + Method method = RoutingHandler.class.getMethod("add", HttpString.class, String.class, HttpHandler.class); + Object[] arguments = new Object[]{Methods.GET, template, httpHandler}; + interceptor.beforeMethod(enhancedInstance, method, arguments, method.getParameterTypes(), methodInterceptResult); + interceptor.afterMethod(enhancedInstance, method, arguments, method.getParameterTypes(), null); + assertTrue(arguments[2] instanceof TracingHandler); + } + + @Test + public void testStatusCodeIsOk() throws Throwable { + TracingHandler handler = new TracingHandler(template, httpHandler); + HttpServerExchange exchange = buildExchange(); + handler.handleRequest(exchange); + exchange.endExchange(); + assertThat(segmentStorage.getTraceSegments().size(), is(1)); + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + List spans = SegmentHelper.getSpans(traceSegment); + assertHttpSpan(spans.get(0)); + } + + @Test + public void testStatusCodeIsNotOk() throws Throwable { + TracingHandler handler = new TracingHandler(template, httpHandler); + HttpServerExchange exchange = buildExchange(); + exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR); + handler.handleRequest(exchange); + exchange.endExchange(); + assertThat(segmentStorage.getTraceSegments().size(), is(1)); + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + List spans = SegmentHelper.getSpans(traceSegment); + assertHttpSpan(spans.get(0)); + assertThat(SpanHelper.getErrorOccurred(spans.get(0)), is(true)); + } + + private HttpServerExchange buildExchange() { + HeaderMap requestHeaders = new HeaderMap(); + HeaderMap responseHeaders = new HeaderMap(); + HttpServerExchange exchange = new HttpServerExchange(serverConnection, requestHeaders, responseHeaders, 0); + exchange.setRequestURI(uri); + exchange.setRequestPath(uri); + exchange.setDestinationAddress(new InetSocketAddress("localhost", 8080)); + exchange.setRequestScheme("http"); + exchange.setRequestMethod(Methods.GET); + return exchange; + } + + private void assertHttpSpan(AbstractTracingSpan span) { + assertThat(span.getOperationName(), is(template)); + assertComponent(span, ComponentsDefine.UNDERTOW); + SpanAssert.assertTag(span, 0, "http://localhost:8080" + uri); + assertThat(span.isEntry(), is(true)); + SpanAssert.assertLayer(span, SpanLayer.HTTP); + } + +} diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/ExecuteRootHandlerInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/TracingHandlerTest.java similarity index 55% rename from apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/ExecuteRootHandlerInterceptorTest.java rename to apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/TracingHandlerTest.java index 5619cc87d..618915641 100644 --- a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/ExecuteRootHandlerInterceptorTest.java +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/TracingHandlerTest.java @@ -15,7 +15,6 @@ * limitations under the License. * */ - package org.apache.skywalking.apm.plugin.undertow.v2x; import io.undertow.server.HttpHandler; @@ -23,18 +22,14 @@ import io.undertow.server.HttpServerExchange; import io.undertow.server.ServerConnection; import io.undertow.util.HeaderMap; import io.undertow.util.HttpString; -import java.net.InetSocketAddress; -import java.util.List; +import io.undertow.util.Methods; +import io.undertow.util.StatusCodes; import org.apache.skywalking.apm.agent.core.conf.Config; import org.apache.skywalking.apm.agent.core.context.SW3CarrierItem; import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan; -import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity; import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer; import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment; import org.apache.skywalking.apm.agent.core.context.trace.TraceSegmentRef; -import org.apache.skywalking.apm.agent.core.context.util.TagValuePair; -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.test.helper.SegmentHelper; import org.apache.skywalking.apm.agent.test.helper.SegmentRefHelper; import org.apache.skywalking.apm.agent.test.helper.SpanHelper; @@ -44,9 +39,7 @@ import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint; import org.apache.skywalking.apm.agent.test.tools.SpanAssert; import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner; import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; +import org.apache.skywalking.apm.plugin.undertow.v2x.handler.TracingHandler; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -54,76 +47,67 @@ import org.mockito.Mock; import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunnerDelegate; +import java.net.InetSocketAddress; +import java.util.List; + import static org.apache.skywalking.apm.agent.test.tools.SpanAssert.assertComponent; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; /** - * @author chenpengfei + * @author AI + * 2019-07-29 */ @RunWith(PowerMockRunner.class) @PowerMockRunnerDelegate(TracingSegmentRunner.class) -public class ExecuteRootHandlerInterceptorTest { - - private ExecuteRootHandlerInterceptor executeRootHandlerInterceptor; - +public class TracingHandlerTest { @SegmentStoragePoint private SegmentStorage segmentStorage; - @Rule public AgentServiceRule serviceRule = new AgentServiceRule(); - @Mock private HttpHandler httpHandler; - private HttpServerExchange exchange; @Mock ServerConnection serverConnection; - private HeaderMap requestHeaders = new HeaderMap(); - private HeaderMap responseHeaders = new HeaderMap(); - private Object[] arguments; - private Class[] argumentType; + private String template = "/projects/{projectId}/users"; + private String uri = "/projects/{projectId}/users"; - @Mock - private MethodInterceptResult methodInterceptResult; - - @Before - public void setUp() throws Exception { - Config.Agent.ACTIVE_V1_HEADER = true; - executeRootHandlerInterceptor = new ExecuteRootHandlerInterceptor(); - exchange = new HttpServerExchange(serverConnection, requestHeaders, responseHeaders, 0); - exchange.setRequestURI("/test/testRequestURL"); - exchange.setRequestPath("/test/testRequestURL"); - exchange.setDestinationAddress(new InetSocketAddress("localhost", 8080)); - exchange.setRequestScheme("http"); - exchange.setRequestMethod(HttpString.tryFromString("POST")); - arguments = new Object[] {httpHandler, exchange}; - argumentType = new Class[] {httpHandler.getClass(), exchange.getClass()}; - } - - @After - public void clear() { - Config.Agent.ACTIVE_V1_HEADER = false; - } @Test - public void testWithoutSerializedContextData() throws Throwable { - executeRootHandlerInterceptor.beforeMethod(EnhancedInstance.class, null, arguments, argumentType, methodInterceptResult); - executeRootHandlerInterceptor.afterMethod(EnhancedInstance.class, null, arguments, argumentType, null); - + public void testStatusCodeIsOk() throws Throwable { + TracingHandler handler = new TracingHandler(template, httpHandler); + HttpServerExchange exchange = buildExchange(); + handler.handleRequest(exchange); + exchange.endExchange(); assertThat(segmentStorage.getTraceSegments().size(), is(1)); TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); List spans = SegmentHelper.getSpans(traceSegment); - assertHttpSpan(spans.get(0)); } @Test - public void testWithSerializedContextData() throws Throwable { - requestHeaders.put(HttpString.tryFromString(SW3CarrierItem.HEADER_NAME), "1.234.111|3|1|1|#192.168.1.8:18002|#/portal/|#/testEntrySpan|#AQA*#AQA*Et0We0tQNQA*"); + public void testStatusCodeIsNotOk() throws Throwable { + TracingHandler handler = new TracingHandler(template, httpHandler); + HttpServerExchange exchange = buildExchange(); + exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR); + handler.handleRequest(exchange); + exchange.endExchange(); + assertThat(segmentStorage.getTraceSegments().size(), is(1)); + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + List spans = SegmentHelper.getSpans(traceSegment); + assertHttpSpan(spans.get(0)); + assertThat(SpanHelper.getErrorOccurred(spans.get(0)), is(true)); + } - executeRootHandlerInterceptor.beforeMethod(EnhancedInstance.class, null, arguments, argumentType, methodInterceptResult); - executeRootHandlerInterceptor.afterMethod(EnhancedInstance.class, null, arguments, argumentType, null); + @Test + public void testWithSerializedContextData() throws Throwable { + Config.Agent.ACTIVE_V1_HEADER = true; + TracingHandler handler = new TracingHandler(httpHandler); + HttpServerExchange exchange = buildExchange(); + exchange.getRequestHeaders().put(HttpString.tryFromString(SW3CarrierItem.HEADER_NAME), "1.234.111|3|1|1|#192.168.1.8:18002|#/portal/|#/testEntrySpan|#AQA*#AQA*Et0We0tQNQA*"); + handler.handleRequest(exchange); + exchange.endExchange(); assertThat(segmentStorage.getTraceSegments().size(), is(1)); TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); @@ -131,42 +115,27 @@ public class ExecuteRootHandlerInterceptorTest { assertHttpSpan(spans.get(0)); assertTraceSegmentRef(traceSegment.getRefs().get(0)); + Config.Agent.ACTIVE_V1_HEADER = false; } - @Test - public void testStatusCodeNotEquals200() throws Throwable { - exchange.setStatusCode(500); - executeRootHandlerInterceptor.beforeMethod(EnhancedInstance.class, null, arguments, argumentType, methodInterceptResult); - executeRootHandlerInterceptor.afterMethod(EnhancedInstance.class, null, arguments, argumentType, null); - - Assert.assertThat(segmentStorage.getTraceSegments().size(), is(1)); - TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); - List spans = SegmentHelper.getSpans(traceSegment); - - assertThat(spans.size(), is(1)); - - List tags = SpanHelper.getTags(spans.get(0)); - assertThat(tags.size(), is(3)); - assertThat(tags.get(2).getValue(), is("500")); - - assertHttpSpan(spans.get(0)); - assertThat(SpanHelper.getErrorOccurred(spans.get(0)), is(true)); + private HttpServerExchange buildExchange() { + HeaderMap requestHeaders = new HeaderMap(); + HeaderMap responseHeaders = new HeaderMap(); + HttpServerExchange exchange = new HttpServerExchange(serverConnection, requestHeaders, responseHeaders, 0); + exchange.setRequestURI(uri); + exchange.setRequestPath(uri); + exchange.setDestinationAddress(new InetSocketAddress("localhost", 8080)); + exchange.setRequestScheme("http"); + exchange.setRequestMethod(Methods.GET); + return exchange; } - @Test - public void testWithUndertowException() throws Throwable { - executeRootHandlerInterceptor.beforeMethod(EnhancedInstance.class, null, arguments, argumentType, methodInterceptResult); - executeRootHandlerInterceptor.handleMethodException(EnhancedInstance.class, null, arguments, argumentType, new RuntimeException()); - executeRootHandlerInterceptor.afterMethod(EnhancedInstance.class, null, arguments, argumentType, null); - - assertThat(segmentStorage.getTraceSegments().size(), is(1)); - TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); - List spans = SegmentHelper.getSpans(traceSegment); - - assertHttpSpan(spans.get(0)); - List logDataEntities = SpanHelper.getLogs(spans.get(0)); - assertThat(logDataEntities.size(), is(1)); - SpanAssert.assertException(logDataEntities.get(0), RuntimeException.class); + private void assertHttpSpan(AbstractTracingSpan span) { + assertThat(span.getOperationName(), is(template)); + assertComponent(span, ComponentsDefine.UNDERTOW); + SpanAssert.assertTag(span, 0, "http://localhost:8080" + uri); + assertThat(span.isEntry(), is(true)); + SpanAssert.assertLayer(span, SpanLayer.HTTP); } private void assertTraceSegmentRef(TraceSegmentRef ref) { @@ -175,11 +144,4 @@ public class ExecuteRootHandlerInterceptorTest { assertThat(SegmentRefHelper.getTraceSegmentId(ref).toString(), is("1.234.111")); } - private void assertHttpSpan(AbstractTracingSpan span) { - assertThat(span.getOperationName(), is("/test/testRequestURL")); - assertComponent(span, ComponentsDefine.UNDERTOW); - SpanAssert.assertTag(span, 0, "http://localhost:8080/test/testRequestURL"); - assertThat(span.isEntry(), is(true)); - SpanAssert.assertLayer(span, SpanLayer.HTTP); - } -} \ No newline at end of file +} diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/UndertowBuilderMethodMatcherTest.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/UndertowBuilderMethodMatcherTest.java new file mode 100644 index 000000000..faba00869 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/UndertowBuilderMethodMatcherTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.skywalking.apm.plugin.undertow.v2x; + +import io.undertow.Undertow; +import io.undertow.predicate.Predicate; +import io.undertow.server.HttpHandler; +import io.undertow.server.RoutingHandler; +import io.undertow.util.HttpString; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.skywalking.apm.plugin.undertow.v2x.define.RoutingHandlerInstrumentation; +import org.apache.skywalking.apm.plugin.undertow.v2x.define.UndertowListenerConfigInstrumentation; +import org.junit.Assert; +import org.junit.Test; + +import java.lang.reflect.Method; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +/** + * @author AI + * 2019-08-10 + */ +public class UndertowBuilderMethodMatcherTest { + + @Test + public void testMatch() throws Throwable { + ElementMatcher matcher = named("addHttpListener").and(takesArgument(2, HttpHandler.class)); + Method method = Undertow.Builder.class.getMethod("addHttpListener", int.class, String.class, HttpHandler.class); + MethodDescription md = new MethodDescription.ForLoadedMethod(method); + boolean r = matcher.matches(md); + Assert.assertTrue(r); + } + + @Test + public void testMatchRoutingHandler() throws Throwable { + ElementMatcher matcher = RoutingHandlerInstrumentation.getRoutingHandlerMethodMatcher(); + Method method1 = RoutingHandler.class.getMethod("add", HttpString.class, String.class, HttpHandler.class); + Method method2 = RoutingHandler.class.getMethod("add", HttpString.class, String.class, Predicate.class, HttpHandler.class); + Assert.assertTrue(matcher.matches(new MethodDescription.ForLoadedMethod(method1))); + Assert.assertTrue(matcher.matches(new MethodDescription.ForLoadedMethod(method2))); + } + + @Test + public void testMatcListenerConfig() throws Throwable { + ElementMatcher matcher = UndertowListenerConfigInstrumentation.getUndertowBuilderMethodMatcher(); + Method method = Undertow.Builder.class.getMethod("addListener", Undertow.ListenerBuilder.class); + Assert.assertTrue(matcher.matches(new MethodDescription.ForLoadedMethod(method))); + } +}