diff --git a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java index 1b5a1c6c0a71d0164bdc11fd28bb56e4e6bec304..ee154374cceeeeea9b74fc6b3d7aa2117c9b2b05 100644 --- a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java +++ b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java @@ -98,6 +98,8 @@ public class ComponentsDefine { public static final OfficialComponent TRANSPORT_CLIENT = new OfficialComponent(48, "transport-client"); + public static final OfficialComponent UNDERTOW = new OfficialComponent(49, "Undertow"); + private static ComponentsDefine INSTANCE = new ComponentsDefine(); private String[] components; @@ -107,7 +109,7 @@ public class ComponentsDefine { } public ComponentsDefine() { - components = new String[47]; + components = new String[50]; addComponent(TOMCAT); addComponent(HTTPCLIENT); addComponent(DUBBO); @@ -143,8 +145,7 @@ public class ComponentsDefine { addComponent(SOFARPC); addComponent(ACTIVEMQ_PRODUCER); addComponent(ACTIVEMQ_CONSUMER); - - + addComponent(UNDERTOW); } private void addComponent(OfficialComponent component) { diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml index e06a22fc1dbb132596144d25d08fec56cd986337..ff75c971c68ab55e9185b83259ab707da7bc29c9 100644 --- a/apm-sniffer/apm-sdk-plugin/pom.xml +++ b/apm-sniffer/apm-sdk-plugin/pom.xml @@ -59,6 +59,7 @@ sofarpc-plugin activemq-5.x-plugin elasticsearch-5.x-plugin + undertow-plugins pom diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/pom.xml b/apm-sniffer/apm-sdk-plugin/undertow-plugins/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..85b33a70d6db10bb44a294bfbabcce0e7c31a6bc --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.apache.skywalking + apm-sdk-plugin + 6.0.0-alpha-SNAPSHOT + + + undertow-plugins + + undertow-2.x-plugin + + pom + + undertow-plugins + http://maven.apache.org + + + UTF-8 + /.. + + diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..2370a4da61662e62f852d78d400bb9304a176731 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/pom.xml @@ -0,0 +1,54 @@ + + + + + undertow-plugins + org.apache.skywalking + 6.0.0-alpha-SNAPSHOT + + 4.0.0 + + apm-undertow-2.x-plugin + jar + + undertow-2.x-plugin + http://maven.apache.org + + + 2.0.9.Final + 3.1.0 + + + + + io.undertow + undertow-core + ${undertow.version} + provided + + + javax.servlet + javax.servlet-api + ${servlet-api.version} + test + + + diff --git a/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/Constants.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/Constants.java new file mode 100644 index 0000000000000000000000000000000000000000..ac8b2082c41040bf7ee7ccee70c855c1ebe9d9a7 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/Constants.java @@ -0,0 +1,27 @@ +/* + * 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; + +/** + * @author chenpengfei + */ +public class Constants { + public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG"; +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..6afb43c048235245828893779f4585e4005544f5 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/ExecuteRootHandlerInterceptor.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.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/ForwardInterceptor.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/ForwardInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..3640d530e408bb073d11ee1ee42d85b0907765b3 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/ForwardInterceptor.java @@ -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. + * + * + */ + +package org.apache.skywalking.apm.plugin.undertow.v2x; + +import org.apache.skywalking.apm.agent.core.context.ContextManager; +import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * @author chenpengfei + */ +public class ForwardInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor { + + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, MethodInterceptResult result) throws Throwable { + if (ContextManager.isActive()) { + AbstractSpan abstractTracingSpan = ContextManager.activeSpan(); + Map eventMap = new HashMap(); + eventMap.put("forward-url", objInst.getSkyWalkingDynamicField() == null ? "" : String.valueOf(objInst.getSkyWalkingDynamicField())); + abstractTracingSpan.log(System.currentTimeMillis(), eventMap); + ContextManager.getRuntimeContext().put(Constants.FORWARD_REQUEST_FLAG, true); + } + } + + @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) { + + } + + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + objInst.setSkyWalkingDynamicField(allArguments[0]); + } +} 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/RequestDispatcherImplInstrumentation.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/undertow/v2x/define/RequestDispatcherImplInstrumentation.java new file mode 100644 index 0000000000000000000000000000000000000000..9ab7b0421b4c6ac6c007ff2b924f0a23dd1714d3 --- /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/RequestDispatcherImplInstrumentation.java @@ -0,0 +1,85 @@ +/* + * 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 chenpengfei + */ +public class RequestDispatcherImplInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + private static final String ENHANCE_CLASS = "io.undertow.servlet.spec.RequestDispatcherImpl"; + private static final String ENHANCE_METHOD = "forward"; + public static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.undertow.v2x.ForwardInterceptor"; + + @Override + protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[] { + new ConstructorInterceptPoint() { + @Override + public ElementMatcher getConstructorMatcher() { + return takesArgumentWithType(0, "java.lang.String"); + } + + @Override + public String getConstructorInterceptor() { + return INTERCEPTOR_CLASS; + } + } + }; + } + + @Override + protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return named(ENHANCE_METHOD); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPTOR_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @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/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/UndertowInstrumentation.java new file mode 100644 index 0000000000000000000000000000000000000000..7c27e92a0742ee5712e20722a95eeab681f06720 --- /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/UndertowInstrumentation.java @@ -0,0 +1,65 @@ +/* + * 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.StaticMethodsInterceptPoint; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassStaticMethodsEnhancePluginDefine; +import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch; +import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +/** + * @author chenpengfei + */ +public class UndertowInstrumentation extends ClassStaticMethodsEnhancePluginDefine { + + 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"; + + @Override + protected ClassMatch enhanceClass() { + return NameMatch.byName(ENHANCE_CLASS); + } + + @Override + protected StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() { + return new StaticMethodsInterceptPoint[] { + new StaticMethodsInterceptPoint() { + @Override + public ElementMatcher getMethodsMatcher() { + return named(ENHANCE_METHOD); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPTOR_CLASS; + } + + @Override public boolean isOverrideArgs() { + return false; + } + } + }; + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..a6070c618a6b8a8dc6e9b5d0500ac2ce8e3502fb --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/main/resources/skywalking-plugin.def @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +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 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/ExecuteRootHandlerInterceptorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..993942503e2074bcbffe8f547ae627cb8c66aa89 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/ExecuteRootHandlerInterceptorTest.java @@ -0,0 +1,179 @@ +/* + * 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.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.KeyValuePair; +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; +import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule; +import org.apache.skywalking.apm.agent.test.tools.SegmentStorage; +import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint; +import org.apache.skywalking.apm.agent.test.tools.SpanAssert; +import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner; +import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.modules.junit4.PowerMockRunnerDelegate; + +import java.net.InetSocketAddress; +import java.util.List; + +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.ServerConnection; +import io.undertow.util.HeaderMap; +import io.undertow.util.HttpString; + +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 + */ +@RunWith(PowerMockRunner.class) +@PowerMockRunnerDelegate(TracingSegmentRunner.class) +public class ExecuteRootHandlerInterceptorTest { + + private ExecuteRootHandlerInterceptor executeRootHandlerInterceptor; + + @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; + + @Mock + private MethodInterceptResult methodInterceptResult; + + @Before + public void setUp() throws Exception { + 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()}; + } + + @Test + public void testWithoutSerializedContextData() throws Throwable { + executeRootHandlerInterceptor.beforeMethod(EnhancedInstance.class, null, arguments, argumentType, methodInterceptResult); + 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)); + } + + @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*"); + + executeRootHandlerInterceptor.beforeMethod(EnhancedInstance.class, null, arguments, argumentType, methodInterceptResult); + 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)); + assertTraceSegmentRef(traceSegment.getRefs().get(0)); + } + + @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)); + } + + @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 assertTraceSegmentRef(TraceSegmentRef ref) { + assertThat(SegmentRefHelper.getEntryApplicationInstanceId(ref), is(1)); + assertThat(SegmentRefHelper.getSpanId(ref), is(3)); + 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/ForwardInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/ForwardInterceptorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0ca917a66334f89ef203c9cb814dc0590a88cc1e --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/undertow-plugins/undertow-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/undertow/v2x/ForwardInterceptorTest.java @@ -0,0 +1,103 @@ +/* + * 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.ContextManager; +import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; +import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity; +import org.apache.skywalking.apm.agent.core.context.util.KeyValuePair; +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.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.TracingSegmentRunner; +import org.hamcrest.CoreMatchers; +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.util.List; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.when; + +/** + * @author chenpengfei + */ +@RunWith(PowerMockRunner.class) +@PowerMockRunnerDelegate(TracingSegmentRunner.class) +public class ForwardInterceptorTest { + + private ForwardInterceptor forwardInterceptor; + + @SegmentStoragePoint + private SegmentStorage segmentStorage; + + @Rule + public AgentServiceRule serviceRule = new AgentServiceRule(); + + @Mock + ServletRequest request; + @Mock + ServletResponse response; + + @Mock + private MethodInterceptResult methodInterceptResult; + + @Mock + private EnhancedInstance enhancedInstance; + + private Object[] arguments; + private Class[] argumentType; + + @Before + public void setUp() throws Exception { + forwardInterceptor = new ForwardInterceptor(); + when(enhancedInstance.getSkyWalkingDynamicField()).thenReturn("http://localhost:8080/test/testRequestURL"); + arguments = new Object[]{request, response}; + argumentType = new Class[]{request.getClass(), response.getClass()}; + } + + @Test + public void testWithoutSerializedContextData() throws Throwable { + AbstractSpan span = ContextManager.createLocalSpan("/testForward"); + forwardInterceptor.onConstruct(enhancedInstance, arguments); + forwardInterceptor.beforeMethod(enhancedInstance, null, arguments, argumentType, methodInterceptResult); + forwardInterceptor.afterMethod(enhancedInstance, null, arguments, argumentType, null); + + List logDataEntities = SpanHelper.getLogs(span); + assertThat(logDataEntities.size(), is(1)); + List logs = logDataEntities.get(0).getLogs(); + assertThat(logs.size(), is(1)); + assertThat(logs.get(0).getKey(), is("forward-url")); + assertThat(logs.get(0).getValue(), is("http://localhost:8080/test/testRequestURL")); + + assertThat(ContextManager.getRuntimeContext().get(Constants.FORWARD_REQUEST_FLAG), CoreMatchers.is(true)); + } +} \ No newline at end of file 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 243d698875b1b79b20fddabd4bffceb5f0185ad6..b2fc63ed3305c4e8164868b50c56abab9de91e12 100644 --- a/docs/en/setup/service-agent/java-agent/Supported-list.md +++ b/docs/en/setup/service-agent/java-agent/Supported-list.md @@ -9,6 +9,7 @@ * [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 + * [Undertow](http://undertow.io/) 2.0.0.Final -> 2.0.13.Final * HTTP Client * [Feign](https://github.com/OpenFeign/feign) 9.x * [Netflix Spring Cloud Feign](https://github.com/spring-cloud/spring-cloud-netflix/tree/master/spring-cloud-starter-feign) 1.1.x, 1.2.x, 1.3.x diff --git a/oap-server/server-core/src/test/resources/component-libraries.yml b/oap-server/server-core/src/test/resources/component-libraries.yml index 7291c7f7e2386aacf6bd64d5c655d7c4e84f8790..ab20b468f4bac3b7d70df686dffd335fd7e487da 100644 --- a/oap-server/server-core/src/test/resources/component-libraries.yml +++ b/oap-server/server-core/src/test/resources/component-libraries.yml @@ -171,6 +171,9 @@ Elasticsearch: transport-client: id: 48 languages: Java +Undertow: + id: 49 + languages: Java # .NET/.NET Core components # [3000, 4000) for C#/.NET only