diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/pom.xml new file mode 100644 index 000000000..bc51af148 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/pom.xml @@ -0,0 +1,42 @@ + + + + + jetty-plugins + org.apache.skywalking + 5.0.0-alpha + + 4.0.0 + + apm-jetty-client-9.0-plugin + jar + + jetty-client-9.0-plugin + http://maven.apache.org + + + + org.eclipse.jetty + jetty-client + 9.0.0.v20130308 + provided + + + diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/SyncHttpRequestSendInterceptor.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/SyncHttpRequestSendInterceptor.java new file mode 100644 index 000000000..0313bf401 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/SyncHttpRequestSendInterceptor.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.jetty.v90.client; + +import java.lang.reflect.Method; +import org.apache.skywalking.apm.agent.core.context.CarrierItem; +import org.apache.skywalking.apm.agent.core.context.ContextCarrier; +import org.apache.skywalking.apm.agent.core.context.ContextManager; +import org.apache.skywalking.apm.agent.core.context.tag.Tags; +import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; +import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; +import org.eclipse.jetty.client.HttpRequest; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpMethod; + +public class SyncHttpRequestSendInterceptor implements InstanceMethodsAroundInterceptor { + + @Override + public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + MethodInterceptResult result) throws Throwable { + HttpRequest request = (HttpRequest)objInst; + ContextCarrier contextCarrier = new ContextCarrier(); + AbstractSpan span = ContextManager.createExitSpan(request.getURI().getPath(), contextCarrier, request.getHost() + ":" + request.getPort()); + span.setComponent(ComponentsDefine.JETTY_CLIENT); + + Tags.HTTP.METHOD.set(span, getHttpMethod(request)); + Tags.URL.set(span, request.getURI().toString()); + SpanLayer.asHttp(span); + + CarrierItem next = contextCarrier.items(); + HttpFields field = request.getHeaders(); + while (next.hasNext()) { + next = next.next(); + field.add(next.getHeadKey(), next.getHeadValue()); + } + } + + @Override + public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, + Object ret) throws Throwable { + ContextManager.stopSpan(); + return ret; + } + + @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + ContextManager.activeSpan().errorOccurred().log(t); + } + + public String getHttpMethod(HttpRequest request) { + HttpMethod httpMethod = HttpMethod.GET; + + /** + * The method is null if the client using GET method. + * + * @see org.eclipse.jetty.client.HttpRequest#GET(String uri) + * @see org.eclipse.jetty.client.HttpRequest( org.eclipse.jetty.client.HttpClient client, long conversation, java.net.URI uri) + */ + if (request.getMethod() != null) { + httpMethod = request.getMethod(); + } + + return httpMethod.name(); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/define/HttpRequestInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/define/HttpRequestInstrumentation.java new file mode 100644 index 000000000..62d5b87b5 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v90/client/define/HttpRequestInstrumentation.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.jetty.v90.client.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 org.apache.skywalking.apm.agent.core.plugin.match.NameMatch; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +/** + * {@link HttpRequestInstrumentation} enhance the send method without argument in + * org.eclipse.jetty.client.HttpRequest by org.apache.skywalking.apm.plugin.jetty.client.SyncHttpRequestSendInterceptor + * and enhance the send with org.eclipse.jetty.client.api.Response$CompleteListener parameter + * by org.apache.skywalking.apm.plugin.jetty.client.AsyncHttpRequestSendInterceptor + * + * @author zhangxin + */ +public class HttpRequestInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + private static final String ENHANCE_CLASS = "org.eclipse.jetty.client.HttpRequest"; + private static final String ENHANCE_CLASS_NAME = "send"; + public static final String SYNC_SEND_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jetty.v90.client.SyncHttpRequestSendV90Interceptor"; + + @Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[0]; + } + + @Override protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new InstanceMethodsInterceptPoint() { + //sync call interceptor point + @Override public ElementMatcher getMethodsMatcher() { + return named(ENHANCE_CLASS_NAME).and(takesArguments(0)); + } + + @Override public String getMethodsInterceptor() { + return SYNC_SEND_INTERCEPTOR; + } + + @Override public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override protected ClassMatch enhanceClass() { + return NameMatch.byName(ENHANCE_CLASS); + } + + @Override protected String[] witnessClasses() { + return new String[] {"org.eclipse.jetty.client.api.ProxyConfiguration"}; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/resources/skywalking-plugin.def new file mode 100644 index 000000000..05bc01091 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/main/resources/skywalking-plugin.def @@ -0,0 +1 @@ +jetty-client-9.0=org.apache.skywalking.apm.plugin.jetty.v90.client.define.HttpRequestInstrumentation diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v90/client/SyncHttpRequestSendInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v90/client/SyncHttpRequestSendInterceptorTest.java new file mode 100644 index 000000000..f666301cd --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.0-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v90/client/SyncHttpRequestSendInterceptorTest.java @@ -0,0 +1,141 @@ +/* + * 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.jetty.v90.client; + +import java.net.URI; +import java.util.List; +import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan; +import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment; +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.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.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.HttpRequest; +import org.eclipse.jetty.http.HttpMethod; +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 org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +@RunWith(PowerMockRunner.class) +@PowerMockRunnerDelegate(TracingSegmentRunner.class) +public class SyncHttpRequestSendInterceptorTest { + + @SegmentStoragePoint + private SegmentStorage segmentStorage; + @Rule + public AgentServiceRule serviceRule = new AgentServiceRule(); + @Mock + private HttpClient httpClient; + @Mock + private EnhancedInstance callBackEnhanceInstance; + + private Object[] allArguments; + private Class[] argumentTypes; + private MockHttpRequest enhancedInstance; + private SyncHttpRequestSendInterceptor interceptor; + private URI uri = URI.create("http://localhost:8080/test"); + + @Before + public void setUp() throws Exception { + enhancedInstance = new MockHttpRequest(httpClient, uri); + allArguments = new Object[] {"OperationKey", "OperationValue"}; + argumentTypes = new Class[] {String.class, String.class}; + + interceptor = new SyncHttpRequestSendInterceptor(); + allArguments = new Object[] {callBackEnhanceInstance}; + } + + @Test + public void testMethodsAround() throws Throwable { + interceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, null); + interceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, null); + + assertThat(segmentStorage.getTraceSegments().size(), is(1)); + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + + Assert.assertEquals(1, SegmentHelper.getSpans(traceSegment).size()); + AbstractTracingSpan finishedSpan = SegmentHelper.getSpans(traceSegment).get(0); + + List tags = SpanHelper.getTags(finishedSpan); + assertThat(tags.size(), is(2)); + assertThat(tags.get(0).getValue(), is("GET")); + assertThat(tags.get(1).getValue(), is(uri.toString())); + + Assert.assertEquals(false, SpanHelper.getErrorOccurred(finishedSpan)); + } + + @Test + public void testMethodsAroundError() throws Throwable { + interceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, null); + interceptor.handleMethodException(enhancedInstance, null, allArguments, argumentTypes, new RuntimeException()); + interceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, null); + + assertThat(segmentStorage.getTraceSegments().size(), is(1)); + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + + Assert.assertEquals(1, SegmentHelper.getSpans(traceSegment).size()); + AbstractTracingSpan finishedSpan = SegmentHelper.getSpans(traceSegment).get(0); + + List tags = SpanHelper.getTags(finishedSpan); + assertThat(tags.size(), is(2)); + assertThat(tags.get(0).getValue(), is("GET")); + assertThat(tags.get(1).getValue(), is(uri.toString())); + + Assert.assertEquals(true, SpanHelper.getErrorOccurred(finishedSpan)); + SpanAssert.assertException(SpanHelper.getLogs(finishedSpan).get(0), RuntimeException.class); + + } + + private class MockHttpRequest extends HttpRequest implements EnhancedInstance { + public MockHttpRequest(HttpClient httpClient, URI uri) { + super(httpClient, uri); + } + + @Override public Object getSkyWalkingDynamicField() { + return null; + } + + @Override public void setSkyWalkingDynamicField(Object value) { + + } + + @Override public HttpMethod getMethod() { + return HttpMethod.GET; + } + + @Override public URI getURI() { + return uri; + } + } +} diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/pom.xml index 9730602da..3c13eddc6 100644 --- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/pom.xml +++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/pom.xml @@ -35,7 +35,7 @@ org.eclipse.jetty jetty-client - 9.0.0.v20130308 + 9.1.0.v20131115 provided diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/SyncHttpRequestSendInterceptor.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/SyncHttpRequestSendInterceptor.java index 63fc9c58e..49ac74e9e 100644 --- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/SyncHttpRequestSendInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/SyncHttpRequestSendInterceptor.java @@ -31,7 +31,6 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInt import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; import org.eclipse.jetty.client.HttpRequest; import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpMethod; public class SyncHttpRequestSendInterceptor implements InstanceMethodsAroundInterceptor { @@ -42,19 +41,8 @@ public class SyncHttpRequestSendInterceptor implements InstanceMethodsAroundInte ContextCarrier contextCarrier = new ContextCarrier(); AbstractSpan span = ContextManager.createExitSpan(request.getURI().getPath(), contextCarrier, request.getHost() + ":" + request.getPort()); span.setComponent(ComponentsDefine.JETTY_CLIENT); - HttpMethod httpMethod = HttpMethod.GET; - /** - * The method is null if the client using GET method. - * - * @see org.eclipse.jetty.client.HttpRequest#GET(String uri) - * @see org.eclipse.jetty.client.HttpRequest( org.eclipse.jetty.client.HttpClient client, long conversation, java.net.URI uri) - */ - if (request.getMethod() != null) { - httpMethod = request.getMethod(); - } - - Tags.HTTP.METHOD.set(span, httpMethod.asString()); + Tags.HTTP.METHOD.set(span, getHttpMethod(request)); Tags.URL.set(span, request.getURI().toString()); SpanLayer.asHttp(span); @@ -77,4 +65,14 @@ public class SyncHttpRequestSendInterceptor implements InstanceMethodsAroundInte Class[] argumentsTypes, Throwable t) { ContextManager.activeSpan().errorOccurred().log(t); } + + public String getHttpMethod(HttpRequest request) { + String method = request.getMethod(); + + if (method == null || method.length() == 0) { + method = "GET"; + } + + return method; + } } diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/define/HttpRequestInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/define/HttpRequestInstrumentation.java index 147006dee..53d454e8d 100644 --- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/define/HttpRequestInstrumentation.java +++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/client/define/HttpRequestInstrumentation.java @@ -70,4 +70,8 @@ public class HttpRequestInstrumentation extends ClassInstanceMethodsEnhancePlugi @Override protected ClassMatch enhanceClass() { return NameMatch.byName(ENHANCE_CLASS); } + + @Override protected String[] witnessClasses() { + return new String[] {"org.eclipse.jetty.client.AbstractHttpClientTransport"}; + } } diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/client/SyncHttpRequestSendInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/client/SyncHttpRequestSendInterceptorTest.java index 625e2d059..a084bb04f 100644 --- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/client/SyncHttpRequestSendInterceptorTest.java +++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-client-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/client/SyncHttpRequestSendInterceptorTest.java @@ -16,7 +16,6 @@ * */ - package org.apache.skywalking.apm.plugin.jetty.v9.client; import java.net.URI; @@ -31,9 +30,9 @@ 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.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpRequest; -import org.eclipse.jetty.http.HttpMethod; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -42,7 +41,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunnerDelegate; -import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @@ -130,8 +128,8 @@ public class SyncHttpRequestSendInterceptorTest { } - @Override public HttpMethod getMethod() { - return HttpMethod.GET; + @Override public String getMethod() { + return "GET"; } @Override public URI getURI() { diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jetty-plugin/pom.xml index ec6914976..c80d1c488 100644 --- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/pom.xml +++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/pom.xml @@ -31,6 +31,7 @@ jetty-client-9.x-plugin jetty-server-9.x-plugin + jetty-client-9.0-plugin pom