This is an automated email from the ASF dual-hosted git repository. wusheng pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/skywalking-java.git
The following commit(s) were added to refs/heads/main by this push: new 9101f69 Add okhttp2.x plugin (#49) 9101f69 is described below commit 9101f691fba659a2616918588cae65da25e04690 Author: xu1009 <2933250...@qq.com> AuthorDate: Mon Oct 25 22:40:37 2021 +0800 Add okhttp2.x plugin (#49) Co-authored-by: litexu <lit...@tencent.com> --- .github/workflows/plugins-test.2.yaml | 1 + CHANGES.md | 2 + .../apm-sdk-plugin/okhttp-2.x-plugin/pom.xml | 53 +++++++ .../plugin/okhttp/v2}/AsyncCallInterceptor.java | 57 +------ .../apm/plugin/okhttp/v2/CallInterceptor.java} | 60 ++----- .../apm/plugin/okhttp/v2/EnqueueInterceptor.java} | 40 +++-- .../plugin/okhttp/v2}/OnResponseInterceptor.java | 20 +-- .../apm/plugin/okhttp/v2}/RealCallInterceptor.java | 35 +++-- .../okhttp/v2/define/AsyncCallInstrumentation.java | 83 ++++++++++ .../okhttp/v2/define/CallbackInstrumentation.java | 80 ++++++++++ .../okhttp/v2/define/RealCallInstrumentation.java | 120 ++++++++++++++ .../src/main/resources/skywalking-plugin.def | 19 +++ .../plugin/okhttp/v2/RealCallInterceptorTest.java | 175 +++++++++++++++++++++ .../okhttp/v3/define/RealCallInstrumentation.java | 100 +++++++----- .../okhttp/v4/define/RealCallInstrumentation.java | 101 +++++++----- .../plugin/okhttp/common/AsyncCallInterceptor.java | 53 +------ ...alCallInterceptor.java => CallInterceptor.java} | 48 ++---- .../plugin/okhttp/common/OnFailureInterceptor.java | 3 +- .../okhttp/common/OnResponseInterceptor.java | 8 +- .../plugin/okhttp/common/RealCallInterceptor.java | 18 +-- apm-sniffer/apm-sdk-plugin/pom.xml | 1 + .../setup/service-agent/java-agent/Plugin-list.md | 1 + .../service-agent/java-agent/Supported-list.md | 2 +- pom.xml | 1 + .../okhttp-scenario/config/expectedData.yaml | 49 ++++-- .../scenarios/okhttp2-scenario/bin/startup.sh | 21 +++ .../config/expectedData.yaml | 69 +++++--- .../scenarios/okhttp2-scenario/configuration.yml | 20 +++ test/plugin/scenarios/okhttp2-scenario/pom.xml | 124 +++++++++++++++ .../src/main/assembly/assembly.xml | 41 +++++ .../apm/testcase/okhttp2/Application.java | 34 ++++ .../okhttp2/controller/CaseController.java | 83 ++++++++++ .../src/main/resources/application.yaml | 23 +++ .../okhttp2-scenario/src/main/resources/log4j2.xml | 30 ++++ .../okhttp2-scenario/support-version.list | 22 +++ 35 files changed, 1246 insertions(+), 351 deletions(-) diff --git a/.github/workflows/plugins-test.2.yaml b/.github/workflows/plugins-test.2.yaml index 2ded7f6..44489ee 100644 --- a/.github/workflows/plugins-test.2.yaml +++ b/.github/workflows/plugins-test.2.yaml @@ -78,6 +78,7 @@ jobs: - struts2.3-scenario - struts2.5-scenario - cxf-scenario + - okhttp2-scenario steps: - uses: actions/checkout@v2 with: diff --git a/CHANGES.md b/CHANGES.md index 6218db0..46455b0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -37,6 +37,8 @@ Release Notes. * Fix version compatibility for JsonRPC4J plugin. * Add plugin to support Apache Kylin-jdbc 2.6.x 3.x 4.x * Fix instrumentation v2 API doesn't work for constructor instrumentation. +* Add plugin to support okhttp 2.x +* Optimize okhttp 3.x 4.x plugin to get span time cost precisely #### Documentation diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/pom.xml new file mode 100644 index 0000000..be93a8a --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/pom.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>apm-sdk-plugin</artifactId> + <groupId>org.apache.skywalking</groupId> + <version>8.8.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>okhttp-2.x-plugin</artifactId> + <name>okhttp-2.x-plugin</name> + <packaging>jar</packaging> + + <properties> + <okhttp.version>2.7.5</okhttp.version> + </properties> + + <dependencies> + <dependency> + <groupId>com.squareup.okhttp</groupId> + <artifactId>okhttp</artifactId> + <version>${okhttp.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.skywalking</groupId> + <artifactId>apm-okhttp-common</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> + +</project> \ No newline at end of file diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/AsyncCallInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/AsyncCallInterceptor.java similarity index 57% copy from apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/AsyncCallInterceptor.java copy to apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/AsyncCallInterceptor.java index 54364f4..2163ec1 100644 --- a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/AsyncCallInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/AsyncCallInterceptor.java @@ -16,25 +16,15 @@ * */ -package org.apache.skywalking.apm.plugin.okhttp.common; +package org.apache.skywalking.apm.plugin.okhttp.v2; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.Request; -import org.apache.skywalking.apm.agent.core.context.CarrierItem; -import org.apache.skywalking.apm.agent.core.context.ContextCarrier; +import java.lang.reflect.Method; import org.apache.skywalking.apm.agent.core.context.ContextManager; -import org.apache.skywalking.apm.agent.core.context.tag.Tags; -import org.apache.skywalking.apm.agent.core.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.InstanceConstructorInterceptor; 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 java.lang.reflect.Field; -import java.lang.reflect.Method; +import org.apache.skywalking.apm.plugin.okhttp.common.EnhanceRequiredInfo; /** * {@link AsyncCallInterceptor} get the `EnhanceRequiredInfo` instance from `SkyWalkingDynamicField` and then put it @@ -45,18 +35,6 @@ import java.lang.reflect.Method; */ public class AsyncCallInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor { - private static Field FIELD_HEADERS_OF_REQUEST; - - static { - try { - final Field field = Request.class.getDeclaredField("headers"); - field.setAccessible(true); - FIELD_HEADERS_OF_REQUEST = field; - } catch (Exception ignore) { - FIELD_HEADERS_OF_REQUEST = null; - } - } - @Override public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { /** @@ -71,43 +49,22 @@ public class AsyncCallInterceptor implements InstanceConstructorInterceptor, Ins @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - MethodInterceptResult result) throws Throwable { + MethodInterceptResult result) throws Throwable { EnhanceRequiredInfo enhanceRequiredInfo = (EnhanceRequiredInfo) objInst.getSkyWalkingDynamicField(); - Request request = (Request) enhanceRequiredInfo.getRealCallEnhance().getSkyWalkingDynamicField(); - - HttpUrl requestUrl = request.url(); - AbstractSpan span = ContextManager.createExitSpan(requestUrl.uri() - .getPath(), requestUrl.host() + ":" + requestUrl.port()); + ContextManager.createLocalSpan("Async/execute"); ContextManager.continued(enhanceRequiredInfo.getContextSnapshot()); - ContextCarrier contextCarrier = new ContextCarrier(); - ContextManager.inject(contextCarrier); - span.setComponent(ComponentsDefine.OKHTTP); - Tags.HTTP.METHOD.set(span, request.method()); - Tags.URL.set(span, requestUrl.uri().toString()); - SpanLayer.asHttp(span); - - if (FIELD_HEADERS_OF_REQUEST != null) { - Headers.Builder headerBuilder = request.headers().newBuilder(); - CarrierItem next = contextCarrier.items(); - while (next.hasNext()) { - next = next.next(); - headerBuilder.set(next.getHeadKey(), next.getHeadValue()); - } - FIELD_HEADERS_OF_REQUEST.set(request, headerBuilder.build()); - } - } @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - Object ret) throws Throwable { + Object ret) throws Throwable { ContextManager.stopSpan(); return ret; } @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, - Class<?>[] argumentsTypes, Throwable t) { + Class<?>[] argumentsTypes, Throwable t) { ContextManager.activeSpan().log(t); } } diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/RealCallInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/CallInterceptor.java similarity index 68% copy from apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/RealCallInterceptor.java copy to apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/CallInterceptor.java index c944649..adf5965 100644 --- a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/RealCallInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/CallInterceptor.java @@ -16,12 +16,14 @@ * */ -package org.apache.skywalking.apm.plugin.okhttp.common; +package org.apache.skywalking.apm.plugin.okhttp.v2; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.Request; -import okhttp3.Response; +import com.squareup.okhttp.Headers; +import com.squareup.okhttp.HttpUrl; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; +import java.lang.reflect.Field; +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; @@ -29,18 +31,11 @@ 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.InstanceConstructorInterceptor; 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 java.lang.reflect.Field; -import java.lang.reflect.Method; - -/** - * {@link RealCallInterceptor} intercept the synchronous http calls by the discovery of okhttp. - */ -public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor { +public class CallInterceptor implements InstanceMethodsAroundInterceptor { private static Field FIELD_HEADERS_OF_REQUEST; @@ -55,32 +50,18 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In } @Override - public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { - objInst.setSkyWalkingDynamicField(allArguments[1]); - } - - /** - * Get the {@link Request} from {@link EnhancedInstance}, then create {@link AbstractSpan} and set host, - * port, kind, component, url from {@link Request}. Through the reflection of the way, set the http header - * of context data into {@link Request#headers}. - * - * @param result change this result, if you want to truncate the method. - */ - @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - MethodInterceptResult result) throws Throwable { + MethodInterceptResult result) throws Throwable { Request request = (Request) objInst.getSkyWalkingDynamicField(); - - ContextCarrier contextCarrier = new ContextCarrier(); - HttpUrl requestUrl = request.url(); + HttpUrl requestUrl = request.httpUrl(); AbstractSpan span = ContextManager.createExitSpan(requestUrl.uri() - .getPath(), contextCarrier, requestUrl.host() + ":" + requestUrl - .port()); + .getPath(), requestUrl.host() + ":" + requestUrl.port()); + ContextCarrier contextCarrier = new ContextCarrier(); + ContextManager.inject(contextCarrier); span.setComponent(ComponentsDefine.OKHTTP); Tags.HTTP.METHOD.set(span, request.method()); Tags.URL.set(span, requestUrl.uri().toString()); SpanLayer.asHttp(span); - if (FIELD_HEADERS_OF_REQUEST != null) { Headers.Builder headerBuilder = request.headers().newBuilder(); CarrierItem next = contextCarrier.items(); @@ -92,15 +73,9 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In } } - /** - * Get the status code from {@link Response}, when status code greater than 400, it means there was some errors in - * the server. Finish the {@link AbstractSpan}. - * - * @param ret the method's original return value. - */ @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - Object ret) throws Throwable { + Object ret) throws Throwable { Response response = (Response) ret; if (response != null) { int statusCode = response.code(); @@ -110,16 +85,13 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In Tags.HTTP_RESPONSE_STATUS_CODE.set(span, statusCode); } } - ContextManager.stopSpan(); - return ret; } @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, - Class<?>[] argumentsTypes, Throwable t) { - AbstractSpan abstractSpan = ContextManager.activeSpan(); - abstractSpan.log(t); + Class<?>[] argumentsTypes, Throwable t) { + ContextManager.activeSpan().log(t); } } diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnResponseInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/EnqueueInterceptor.java similarity index 51% copy from apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnResponseInterceptor.java copy to apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/EnqueueInterceptor.java index 62728b3..a487a3d 100644 --- a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnResponseInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/EnqueueInterceptor.java @@ -16,34 +16,47 @@ * */ -package org.apache.skywalking.apm.plugin.okhttp.common; +package org.apache.skywalking.apm.plugin.okhttp.v2; -import okhttp3.Response; +import com.squareup.okhttp.Request; +import java.lang.reflect.Method; import org.apache.skywalking.apm.agent.core.context.ContextManager; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.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 org.apache.skywalking.apm.plugin.okhttp.common.EnhanceRequiredInfo; /** - * {@link OnResponseInterceptor} validate the response code if it is great equal than 400. if so. the transaction status - * chang to `error`, or do nothing. + * {@link EnqueueInterceptor} create a local span and the prefix of the span operation name is start with `Async` when + * the `enqueue` method called and also put the `ContextSnapshot` and `RealCall` instance into the + * `SkyWalkingDynamicField`. */ -public class OnResponseInterceptor implements InstanceMethodsAroundInterceptor { +public class EnqueueInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor { @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable { - Response response = (Response) allArguments[1]; + EnhancedInstance callbackInstance = (EnhancedInstance) allArguments[0]; + Request request = (Request) objInst.getSkyWalkingDynamicField(); + ContextManager.createLocalSpan("Async" + request.httpUrl().uri().getPath()); + + /** + * Here is the process about how to trace the async function. + * + * 1. Storage `Request` object into `RealCall` instance when the constructor of `RealCall` called. + * 2. Put the `RealCall` instance to `CallBack` instance + * 3. Get the `RealCall` instance from `CallBack` and then Put the `RealCall` into `AsyncCall` instance + * since the constructor of `RealCall` called. + * 5. Create the exit span by using the `RealCall` instance when `AsyncCall` method called. + */ - if (response.code() >= 400) { - ContextManager.activeSpan().errorOccurred(); - } + callbackInstance.setSkyWalkingDynamicField(new EnhanceRequiredInfo(objInst, ContextManager.capture())); } @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable { + ContextManager.stopSpan(); return ret; } @@ -52,4 +65,9 @@ public class OnResponseInterceptor implements InstanceMethodsAroundInterceptor { Class<?>[] argumentsTypes, Throwable t) { ContextManager.activeSpan().log(t); } + + @Override + public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { + objInst.setSkyWalkingDynamicField(allArguments[1]); + } } diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnResponseInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/OnResponseInterceptor.java similarity index 83% copy from apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnResponseInterceptor.java copy to apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/OnResponseInterceptor.java index 62728b3..b4b540c 100644 --- a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnResponseInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/OnResponseInterceptor.java @@ -16,40 +16,36 @@ * */ -package org.apache.skywalking.apm.plugin.okhttp.common; +package org.apache.skywalking.apm.plugin.okhttp.v2; -import okhttp3.Response; +import java.lang.reflect.Method; import org.apache.skywalking.apm.agent.core.context.ContextManager; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor; import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; -import java.lang.reflect.Method; - /** * {@link OnResponseInterceptor} validate the response code if it is great equal than 400. if so. the transaction status * chang to `error`, or do nothing. */ public class OnResponseInterceptor implements InstanceMethodsAroundInterceptor { + @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - MethodInterceptResult result) throws Throwable { - Response response = (Response) allArguments[1]; - - if (response.code() >= 400) { - ContextManager.activeSpan().errorOccurred(); - } + MethodInterceptResult result) throws Throwable { + ContextManager.createLocalSpan("Callback/onResponse"); } @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - Object ret) throws Throwable { + Object ret) throws Throwable { + ContextManager.stopSpan(); return ret; } @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, - Class<?>[] argumentsTypes, Throwable t) { + Class<?>[] argumentsTypes, Throwable t) { ContextManager.activeSpan().log(t); } } diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/RealCallInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/RealCallInterceptor.java similarity index 85% copy from apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/RealCallInterceptor.java copy to apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/RealCallInterceptor.java index c944649..2b9387e 100644 --- a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/RealCallInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/RealCallInterceptor.java @@ -16,27 +16,28 @@ * */ -package org.apache.skywalking.apm.plugin.okhttp.common; +package org.apache.skywalking.apm.plugin.okhttp.v2; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.Request; -import okhttp3.Response; +import com.squareup.okhttp.Headers; +import com.squareup.okhttp.HttpUrl; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; +import java.lang.reflect.Field; +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.logging.api.ILog; +import org.apache.skywalking.apm.agent.core.logging.api.LogManager; 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 org.apache.skywalking.apm.network.trace.component.ComponentsDefine; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - /** * {@link RealCallInterceptor} intercept the synchronous http calls by the discovery of okhttp. */ @@ -44,6 +45,8 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In private static Field FIELD_HEADERS_OF_REQUEST; + private static final ILog LOGGER = LogManager.getLogger(RealCallInterceptor.class); + static { try { final Field field = Request.class.getDeclaredField("headers"); @@ -62,20 +65,20 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In /** * Get the {@link Request} from {@link EnhancedInstance}, then create {@link AbstractSpan} and set host, * port, kind, component, url from {@link Request}. Through the reflection of the way, set the http header - * of context data into {@link Request#headers}. + * of context data into {@link Request#headers()}. * * @param result change this result, if you want to truncate the method. */ @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - MethodInterceptResult result) throws Throwable { + MethodInterceptResult result) throws Throwable { Request request = (Request) objInst.getSkyWalkingDynamicField(); ContextCarrier contextCarrier = new ContextCarrier(); - HttpUrl requestUrl = request.url(); - AbstractSpan span = ContextManager.createExitSpan(requestUrl.uri() - .getPath(), contextCarrier, requestUrl.host() + ":" + requestUrl - .port()); + HttpUrl requestUrl = request.httpUrl(); + AbstractSpan span = ContextManager.createExitSpan(requestUrl.uri().getPath(), contextCarrier, + requestUrl.host() + ":" + requestUrl.port()); + ContextManager.inject(contextCarrier); span.setComponent(ComponentsDefine.OKHTTP); Tags.HTTP.METHOD.set(span, request.method()); Tags.URL.set(span, requestUrl.uri().toString()); @@ -100,7 +103,7 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In */ @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - Object ret) throws Throwable { + Object ret) throws Throwable { Response response = (Response) ret; if (response != null) { int statusCode = response.code(); @@ -118,7 +121,7 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, - Class<?>[] argumentsTypes, Throwable t) { + Class<?>[] argumentsTypes, Throwable t) { AbstractSpan abstractSpan = ContextManager.activeSpan(); abstractSpan.log(t); } diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/define/AsyncCallInstrumentation.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/define/AsyncCallInstrumentation.java new file mode 100644 index 0000000..3daa03d --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/define/AsyncCallInstrumentation.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.okhttp.v2.define; + +import static net.bytebuddy.matcher.ElementMatchers.any; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName; + +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; + +public class AsyncCallInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + + /** + * Intercept class. + */ + private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.okhttp.v2.AsyncCallInterceptor"; + + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[]{ + new ConstructorInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getConstructorMatcher() { + return any(); + } + + @Override + public String getConstructorInterceptor() { + return INTERCEPT_CLASS; + } + } + }; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("execute"); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPT_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override + protected ClassMatch enhanceClass() { + return byName("com.squareup.okhttp.Call$AsyncCall"); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/define/CallbackInstrumentation.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/define/CallbackInstrumentation.java new file mode 100644 index 0000000..dd65eb0 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/define/CallbackInstrumentation.java @@ -0,0 +1,80 @@ +/* + * 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.okhttp.v2.define; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch.byHierarchyMatch; + +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; + +public class CallbackInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[0]; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("onFailure"); + } + + @Override + public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.okhttp.common.OnFailureInterceptor"; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + }, + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("onResponse"); + } + + @Override + public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.okhttp.v2.OnResponseInterceptor"; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } + + @Override + protected ClassMatch enhanceClass() { + return byHierarchyMatch(new String[]{"com.squareup.okhttp.Callback"}); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/define/RealCallInstrumentation.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/define/RealCallInstrumentation.java new file mode 100644 index 0000000..aee7fcf --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/define/RealCallInstrumentation.java @@ -0,0 +1,120 @@ +/* + * 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.okhttp.v2.define; + +import static net.bytebuddy.matcher.ElementMatchers.any; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +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; + +public class RealCallInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { + + /** + * Enhance class. + */ + private static final String ENHANCE_CLASS = "com.squareup.okhttp.Call"; + + /** + * Intercept class. + */ + private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.okhttp.v2.RealCallInterceptor"; + + @Override + protected ClassMatch enhanceClass() { + return NameMatch.byName(ENHANCE_CLASS); + } + + @Override + public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { + return new ConstructorInterceptPoint[]{ + new ConstructorInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getConstructorMatcher() { + return any(); + } + + @Override + public String getConstructorInterceptor() { + return INTERCEPT_CLASS; + } + } + }; + } + + @Override + public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("execute"); + } + + @Override + public String getMethodsInterceptor() { + return INTERCEPT_CLASS; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + }, + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("getResponseWithInterceptorChain"); + } + + @Override + public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.okhttp.v2.CallInterceptor"; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + }, + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("enqueue").and(takesArguments(1)); + } + + @Override + public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.okhttp.v2.EnqueueInterceptor"; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + } + }; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/resources/skywalking-plugin.def new file mode 100644 index 0000000..d3772e8 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/resources/skywalking-plugin.def @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +okhttp-2.x=org.apache.skywalking.apm.plugin.okhttp.v2.define.RealCallInstrumentation +okhttp-2.x=org.apache.skywalking.apm.plugin.okhttp.v2.define.CallbackInstrumentation +okhttp-2.x=org.apache.skywalking.apm.plugin.okhttp.v2.define.AsyncCallInstrumentation diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/okhttp/v2/RealCallInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/okhttp/v2/RealCallInterceptorTest.java new file mode 100644 index 0000000..692753f --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/okhttp/v2/RealCallInterceptorTest.java @@ -0,0 +1,175 @@ +/* + * 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.okhttp.v2; + +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.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; +import java.util.List; +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.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.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.modules.junit4.PowerMockRunnerDelegate; + +@RunWith(PowerMockRunner.class) +@PowerMockRunnerDelegate(TracingSegmentRunner.class) +@PrepareForTest({Response.class}) +public class RealCallInterceptorTest { + + @SegmentStoragePoint + private SegmentStorage segmentStorage; + + @Rule + public AgentServiceRule serviceRule = new AgentServiceRule(); + + private RealCallInterceptor realCallInterceptor; + + @Mock + private OkHttpClient client; + + private Request request; + + private Object[] allArguments; + private Class[] argumentTypes; + + private EnhancedInstance enhancedInstance = new EnhancedInstance() { + + private Object object; + + @Override + public Object getSkyWalkingDynamicField() { + return object; + } + + @Override + public void setSkyWalkingDynamicField(Object value) { + this.object = value; + } + }; + + @Before + public void setUp() throws Exception { + request = new Request.Builder().url("http://skywalking.org").build(); + allArguments = new Object[]{ + client, + request, + false + }; + argumentTypes = new Class[]{ + client.getClass(), + request.getClass(), + Boolean.class + }; + realCallInterceptor = new RealCallInterceptor(); + } + + @Test + public void testOnConstruct() { + realCallInterceptor.onConstruct(enhancedInstance, allArguments); + assertThat(enhancedInstance.getSkyWalkingDynamicField(), is(allArguments[1])); + } + + @Test + public void testMethodsAround() throws Throwable { + realCallInterceptor.onConstruct(enhancedInstance, allArguments); + realCallInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, null); + + Response response = mock(Response.class); + when(response.code()).thenReturn(200); + realCallInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, response); + + assertThat(segmentStorage.getTraceSegments().size(), is(1)); + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment); + + assertSpan(spans.get(0)); + SpanAssert.assertOccurException(spans.get(0), false); + } + + @Test + public void testMethodsAroundError() throws Throwable { + realCallInterceptor.onConstruct(enhancedInstance, allArguments); + realCallInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, null); + + Response response = mock(Response.class); + when(response.code()).thenReturn(404); + realCallInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, response); + + assertThat(segmentStorage.getTraceSegments().size(), is(1)); + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment); + + assertSpan(spans.get(0)); + SpanAssert.assertOccurException(spans.get(0), true); + } + + private void assertSpan(AbstractTracingSpan span) { + assertComponent(span, ComponentsDefine.OKHTTP); + SpanAssert.assertLayer(span, SpanLayer.HTTP); + SpanAssert.assertTag(span, 0, "GET"); + SpanAssert.assertTag(span, 1, "http://skywalking.org/"); + assertThat(span.isExit(), is(true)); + assertThat(span.getOperationName(), is("/")); + } + + @Test + public void testException() throws Throwable { + realCallInterceptor.onConstruct(enhancedInstance, allArguments); + realCallInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, null); + + realCallInterceptor.handleMethodException(enhancedInstance, null, allArguments, argumentTypes, + new NullPointerException("testException")); + + Response response = mock(Response.class); + when(response.code()).thenReturn(200); + realCallInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, response); + + assertThat(segmentStorage.getTraceSegments().size(), is(1)); + TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0); + List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment); + + assertSpan(spans.get(0)); + SpanAssert.assertOccurException(spans.get(0), true); + SpanAssert.assertLogSize(spans.get(0), 1); + SpanAssert.assertException(SpanHelper.getLogs(spans.get(0)) + .get(0), NullPointerException.class, "testException"); + } +} diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v3/define/RealCallInstrumentation.java b/apm-sniffer/apm-sdk-plugin/okhttp-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v3/define/RealCallInstrumentation.java index 0658359..9746545 100644 --- a/apm-sniffer/apm-sdk-plugin/okhttp-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v3/define/RealCallInstrumentation.java +++ b/apm-sniffer/apm-sdk-plugin/okhttp-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v3/define/RealCallInstrumentation.java @@ -18,6 +18,10 @@ package org.apache.skywalking.apm.plugin.okhttp.v3.define; +import static net.bytebuddy.matcher.ElementMatchers.any; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.matcher.ElementMatcher; import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; @@ -25,10 +29,6 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsIn 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.any; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArguments; - public class RealCallInstrumentation extends AbstractOkhttpInstrumentation { /** @@ -48,56 +48,72 @@ public class RealCallInstrumentation extends AbstractOkhttpInstrumentation { @Override public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { - return new ConstructorInterceptPoint[] { - new ConstructorInterceptPoint() { - @Override - public ElementMatcher<MethodDescription> getConstructorMatcher() { - return any(); - } + return new ConstructorInterceptPoint[]{ + new ConstructorInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getConstructorMatcher() { + return any(); + } - @Override - public String getConstructorInterceptor() { - return INTERCEPT_CLASS; + @Override + public String getConstructorInterceptor() { + return INTERCEPT_CLASS; + } } - } }; } @Override public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { - return new InstanceMethodsInterceptPoint[] { - new InstanceMethodsInterceptPoint() { - @Override - public ElementMatcher<MethodDescription> getMethodsMatcher() { - return named("execute"); - } + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("execute"); + } - @Override - public String getMethodsInterceptor() { - return INTERCEPT_CLASS; - } + @Override + public String getMethodsInterceptor() { + return INTERCEPT_CLASS; + } - @Override - public boolean isOverrideArgs() { - return false; - } - }, - new InstanceMethodsInterceptPoint() { - @Override - public ElementMatcher<MethodDescription> getMethodsMatcher() { - return named("enqueue").and(takesArguments(1)); - } + @Override + public boolean isOverrideArgs() { + return false; + } + }, + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("getResponseWithInterceptorChain"); + } - @Override - public String getMethodsInterceptor() { - return "org.apache.skywalking.apm.plugin.okhttp.common.EnqueueInterceptor"; - } + @Override + public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.okhttp.common.CallInterceptor"; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + }, + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("enqueue").and(takesArguments(1)); + } + + @Override + public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.okhttp.common.EnqueueInterceptor"; + } - @Override - public boolean isOverrideArgs() { - return false; + @Override + public boolean isOverrideArgs() { + return false; + } } - } }; } } diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v4/define/RealCallInstrumentation.java b/apm-sniffer/apm-sdk-plugin/okhttp-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v4/define/RealCallInstrumentation.java index ea97358..1f7edc8 100644 --- a/apm-sniffer/apm-sdk-plugin/okhttp-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v4/define/RealCallInstrumentation.java +++ b/apm-sniffer/apm-sdk-plugin/okhttp-4.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v4/define/RealCallInstrumentation.java @@ -18,6 +18,11 @@ package org.apache.skywalking.apm.plugin.okhttp.v4.define; +import static net.bytebuddy.matcher.ElementMatchers.any; +import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.matcher.ElementMatcher; import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; @@ -25,10 +30,6 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsIn 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.any; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArguments; - public class RealCallInstrumentation extends AbstractOkhttpInstrumentation { /** @@ -48,56 +49,72 @@ public class RealCallInstrumentation extends AbstractOkhttpInstrumentation { @Override public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { - return new ConstructorInterceptPoint[] { - new ConstructorInterceptPoint() { - @Override - public ElementMatcher<MethodDescription> getConstructorMatcher() { - return any(); - } + return new ConstructorInterceptPoint[]{ + new ConstructorInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getConstructorMatcher() { + return any(); + } - @Override - public String getConstructorInterceptor() { - return INTERCEPT_CLASS; + @Override + public String getConstructorInterceptor() { + return INTERCEPT_CLASS; + } } - } }; } @Override public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { - return new InstanceMethodsInterceptPoint[] { - new InstanceMethodsInterceptPoint() { - @Override - public ElementMatcher<MethodDescription> getMethodsMatcher() { - return named("execute"); - } + return new InstanceMethodsInterceptPoint[]{ + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("execute"); + } - @Override - public String getMethodsInterceptor() { - return INTERCEPT_CLASS; - } + @Override + public String getMethodsInterceptor() { + return INTERCEPT_CLASS; + } - @Override - public boolean isOverrideArgs() { - return false; - } - }, - new InstanceMethodsInterceptPoint() { - @Override - public ElementMatcher<MethodDescription> getMethodsMatcher() { - return named("enqueue").and(takesArguments(1)); - } + @Override + public boolean isOverrideArgs() { + return false; + } + }, + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return nameStartsWith("getResponseWithInterceptorChain"); + } - @Override - public String getMethodsInterceptor() { - return "org.apache.skywalking.apm.plugin.okhttp.common.EnqueueInterceptor"; - } + @Override + public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.okhttp.common.CallInterceptor"; + } + + @Override + public boolean isOverrideArgs() { + return false; + } + }, + new InstanceMethodsInterceptPoint() { + @Override + public ElementMatcher<MethodDescription> getMethodsMatcher() { + return named("enqueue").and(takesArguments(1)); + } + + @Override + public String getMethodsInterceptor() { + return "org.apache.skywalking.apm.plugin.okhttp.common.EnqueueInterceptor"; + } - @Override - public boolean isOverrideArgs() { - return false; + @Override + public boolean isOverrideArgs() { + return false; + } } - } }; } } diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/AsyncCallInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/AsyncCallInterceptor.java index 54364f4..20e966e 100644 --- a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/AsyncCallInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/AsyncCallInterceptor.java @@ -18,23 +18,12 @@ package org.apache.skywalking.apm.plugin.okhttp.common; -import okhttp3.Headers; -import okhttp3.HttpUrl; -import okhttp3.Request; -import org.apache.skywalking.apm.agent.core.context.CarrierItem; -import org.apache.skywalking.apm.agent.core.context.ContextCarrier; +import java.lang.reflect.Method; import org.apache.skywalking.apm.agent.core.context.ContextManager; -import org.apache.skywalking.apm.agent.core.context.tag.Tags; -import org.apache.skywalking.apm.agent.core.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.InstanceConstructorInterceptor; 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 java.lang.reflect.Field; -import java.lang.reflect.Method; /** * {@link AsyncCallInterceptor} get the `EnhanceRequiredInfo` instance from `SkyWalkingDynamicField` and then put it @@ -45,18 +34,6 @@ import java.lang.reflect.Method; */ public class AsyncCallInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor { - private static Field FIELD_HEADERS_OF_REQUEST; - - static { - try { - final Field field = Request.class.getDeclaredField("headers"); - field.setAccessible(true); - FIELD_HEADERS_OF_REQUEST = field; - } catch (Exception ignore) { - FIELD_HEADERS_OF_REQUEST = null; - } - } - @Override public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { /** @@ -71,43 +48,23 @@ public class AsyncCallInterceptor implements InstanceConstructorInterceptor, Ins @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - MethodInterceptResult result) throws Throwable { + MethodInterceptResult result) throws Throwable { EnhanceRequiredInfo enhanceRequiredInfo = (EnhanceRequiredInfo) objInst.getSkyWalkingDynamicField(); - Request request = (Request) enhanceRequiredInfo.getRealCallEnhance().getSkyWalkingDynamicField(); - - HttpUrl requestUrl = request.url(); - AbstractSpan span = ContextManager.createExitSpan(requestUrl.uri() - .getPath(), requestUrl.host() + ":" + requestUrl.port()); + ContextManager.createLocalSpan("Async/execute"); ContextManager.continued(enhanceRequiredInfo.getContextSnapshot()); - ContextCarrier contextCarrier = new ContextCarrier(); - ContextManager.inject(contextCarrier); - span.setComponent(ComponentsDefine.OKHTTP); - Tags.HTTP.METHOD.set(span, request.method()); - Tags.URL.set(span, requestUrl.uri().toString()); - SpanLayer.asHttp(span); - - if (FIELD_HEADERS_OF_REQUEST != null) { - Headers.Builder headerBuilder = request.headers().newBuilder(); - CarrierItem next = contextCarrier.items(); - while (next.hasNext()) { - next = next.next(); - headerBuilder.set(next.getHeadKey(), next.getHeadValue()); - } - FIELD_HEADERS_OF_REQUEST.set(request, headerBuilder.build()); - } } @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - Object ret) throws Throwable { + Object ret) throws Throwable { ContextManager.stopSpan(); return ret; } @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, - Class<?>[] argumentsTypes, Throwable t) { + Class<?>[] argumentsTypes, Throwable t) { ContextManager.activeSpan().log(t); } } diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/RealCallInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/CallInterceptor.java similarity index 71% copy from apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/RealCallInterceptor.java copy to apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/CallInterceptor.java index c944649..90b15a4 100644 --- a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/RealCallInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/CallInterceptor.java @@ -21,6 +21,8 @@ package org.apache.skywalking.apm.plugin.okhttp.common; import okhttp3.Headers; import okhttp3.HttpUrl; import okhttp3.Request; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import okhttp3.Response; import org.apache.skywalking.apm.agent.core.context.CarrierItem; import org.apache.skywalking.apm.agent.core.context.ContextCarrier; @@ -29,18 +31,11 @@ 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.InstanceConstructorInterceptor; 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 java.lang.reflect.Field; -import java.lang.reflect.Method; - -/** - * {@link RealCallInterceptor} intercept the synchronous http calls by the discovery of okhttp. - */ -public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor { +public class CallInterceptor implements InstanceMethodsAroundInterceptor { private static Field FIELD_HEADERS_OF_REQUEST; @@ -55,32 +50,18 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In } @Override - public void onConstruct(EnhancedInstance objInst, Object[] allArguments) { - objInst.setSkyWalkingDynamicField(allArguments[1]); - } - - /** - * Get the {@link Request} from {@link EnhancedInstance}, then create {@link AbstractSpan} and set host, - * port, kind, component, url from {@link Request}. Through the reflection of the way, set the http header - * of context data into {@link Request#headers}. - * - * @param result change this result, if you want to truncate the method. - */ - @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - MethodInterceptResult result) throws Throwable { + MethodInterceptResult result) throws Throwable { Request request = (Request) objInst.getSkyWalkingDynamicField(); - - ContextCarrier contextCarrier = new ContextCarrier(); HttpUrl requestUrl = request.url(); AbstractSpan span = ContextManager.createExitSpan(requestUrl.uri() - .getPath(), contextCarrier, requestUrl.host() + ":" + requestUrl - .port()); + .getPath(), requestUrl.host() + ":" + requestUrl.port()); + ContextCarrier contextCarrier = new ContextCarrier(); + ContextManager.inject(contextCarrier); span.setComponent(ComponentsDefine.OKHTTP); Tags.HTTP.METHOD.set(span, request.method()); Tags.URL.set(span, requestUrl.uri().toString()); SpanLayer.asHttp(span); - if (FIELD_HEADERS_OF_REQUEST != null) { Headers.Builder headerBuilder = request.headers().newBuilder(); CarrierItem next = contextCarrier.items(); @@ -92,15 +73,9 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In } } - /** - * Get the status code from {@link Response}, when status code greater than 400, it means there was some errors in - * the server. Finish the {@link AbstractSpan}. - * - * @param ret the method's original return value. - */ @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - Object ret) throws Throwable { + Object ret) throws Throwable { Response response = (Response) ret; if (response != null) { int statusCode = response.code(); @@ -110,16 +85,13 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In Tags.HTTP_RESPONSE_STATUS_CODE.set(span, statusCode); } } - ContextManager.stopSpan(); - return ret; } @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, - Class<?>[] argumentsTypes, Throwable t) { - AbstractSpan abstractSpan = ContextManager.activeSpan(); - abstractSpan.log(t); + Class<?>[] argumentsTypes, Throwable t) { + ContextManager.activeSpan().log(t); } } diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnFailureInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnFailureInterceptor.java index 8b38b4c..7a75f9d 100644 --- a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnFailureInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnFailureInterceptor.java @@ -29,12 +29,13 @@ public class OnFailureInterceptor implements InstanceMethodsAroundInterceptor { @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable { - ContextManager.activeSpan().log((Throwable) allArguments[1]); + ContextManager.createLocalSpan("Callback/onFailure"); } @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable { + ContextManager.stopSpan(); return ret; } diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnResponseInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnResponseInterceptor.java index 62728b3..b1bd3c1 100644 --- a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnResponseInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/OnResponseInterceptor.java @@ -18,7 +18,6 @@ package org.apache.skywalking.apm.plugin.okhttp.common; -import okhttp3.Response; 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; @@ -34,16 +33,13 @@ public class OnResponseInterceptor implements InstanceMethodsAroundInterceptor { @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable { - Response response = (Response) allArguments[1]; - - if (response.code() >= 400) { - ContextManager.activeSpan().errorOccurred(); - } + ContextManager.createLocalSpan("Callback/onResponse"); } @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable { + ContextManager.stopSpan(); return ret; } diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/RealCallInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/RealCallInterceptor.java index c944649..c305c55 100644 --- a/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/RealCallInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/RealCallInterceptor.java @@ -18,6 +18,8 @@ package org.apache.skywalking.apm.plugin.okhttp.common; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import okhttp3.Headers; import okhttp3.HttpUrl; import okhttp3.Request; @@ -34,9 +36,6 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceM import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - /** * {@link RealCallInterceptor} intercept the synchronous http calls by the discovery of okhttp. */ @@ -62,20 +61,19 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In /** * Get the {@link Request} from {@link EnhancedInstance}, then create {@link AbstractSpan} and set host, * port, kind, component, url from {@link Request}. Through the reflection of the way, set the http header - * of context data into {@link Request#headers}. + * of context data into {@link Request#headers()}. * * @param result change this result, if you want to truncate the method. */ @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - MethodInterceptResult result) throws Throwable { + MethodInterceptResult result) throws Throwable { Request request = (Request) objInst.getSkyWalkingDynamicField(); ContextCarrier contextCarrier = new ContextCarrier(); HttpUrl requestUrl = request.url(); - AbstractSpan span = ContextManager.createExitSpan(requestUrl.uri() - .getPath(), contextCarrier, requestUrl.host() + ":" + requestUrl - .port()); + AbstractSpan span = ContextManager.createExitSpan(requestUrl.uri().getPath(), contextCarrier, + requestUrl.host() + ":" + requestUrl.port()); span.setComponent(ComponentsDefine.OKHTTP); Tags.HTTP.METHOD.set(span, request.method()); Tags.URL.set(span, requestUrl.uri().toString()); @@ -100,7 +98,7 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In */ @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, - Object ret) throws Throwable { + Object ret) throws Throwable { Response response = (Response) ret; if (response != null) { int statusCode = response.code(); @@ -118,7 +116,7 @@ public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, In @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, - Class<?>[] argumentsTypes, Throwable t) { + Class<?>[] argumentsTypes, Throwable t) { AbstractSpan abstractSpan = ContextManager.activeSpan(); abstractSpan.log(t); } diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml index dfafd19..b33edac 100644 --- a/apm-sniffer/apm-sdk-plugin/pom.xml +++ b/apm-sniffer/apm-sdk-plugin/pom.xml @@ -112,6 +112,7 @@ <module>httpclient-5.x-plugin</module> <module>clickhouse-0.3.x-plugin</module> <module>kylin-jdbc-2.6.x-3.x-4.x-plugin</module> + <module>okhttp-2.x-plugin</module> </modules> <packaging>pom</packaging> diff --git a/docs/en/setup/service-agent/java-agent/Plugin-list.md b/docs/en/setup/service-agent/java-agent/Plugin-list.md index e3aa29b..968b968 100644 --- a/docs/en/setup/service-agent/java-agent/Plugin-list.md +++ b/docs/en/setup/service-agent/java-agent/Plugin-list.md @@ -126,3 +126,4 @@ - neo4j-4.x - clickhouse-0.3.x - kylin-jdbc-2.6.x-3.x-4.x +- okhttp-2.x 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 98d49a9..9f5c980 100644 --- a/docs/en/setup/service-agent/java-agent/Supported-list.md +++ b/docs/en/setup/service-agent/java-agent/Supported-list.md @@ -22,7 +22,7 @@ metrics based on the tracing data. * HTTP Client * [Feign](https://github.com/OpenFeign/feign) 9.x * [Netflix Spring Cloud Feign](https://github.com/spring-cloud/spring-cloud-openfeign) 1.1.x -> 2.x - * [Okhttp](https://github.com/square/okhttp) 3.x -> 4.x + * [Okhttp](https://github.com/square/okhttp) 2.x -> 3.x -> 4.x * [Apache httpcomponent HttpClient](http://hc.apache.org/) 2.0 -> 3.1, 4.2, 4.3, 5.0, 5.1 * [Spring RestTemplete](https://github.com/spring-projects/spring-framework) 4.x * [Jetty Client](http://www.eclipse.org/jetty/) 9 diff --git a/pom.xml b/pom.xml index f90d4af..e7249bd 100755 --- a/pom.xml +++ b/pom.xml @@ -391,6 +391,7 @@ <sourceDirectories> <sourceDirectory>${project.build.sourceDirectory}</sourceDirectory> <sourceDirectory>${project.build.testSourceDirectory}</sourceDirectory> +<sourceDirectory>scenarios/okhttp-scenario</sourceDirectory> </sourceDirectories> <resourceIncludes> **/*.properties, diff --git a/test/plugin/scenarios/okhttp-scenario/config/expectedData.yaml b/test/plugin/scenarios/okhttp-scenario/config/expectedData.yaml index fb12e4b..6407771 100644 --- a/test/plugin/scenarios/okhttp-scenario/config/expectedData.yaml +++ b/test/plugin/scenarios/okhttp-scenario/config/expectedData.yaml @@ -56,8 +56,8 @@ segmentItems: - {key: url, value: 'http://127.0.0.1:8080/okhttp-case/case/receiveContext-0'} - {key: http.method, value: GET} refs: - - {parentEndpoint: /okhttp-case/case/receiveContext-0, networkAddress: '127.0.0.1:8080', - refType: CrossProcess, parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not + - {parentEndpoint: Async/execute, networkAddress: '127.0.0.1:8080', + refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not null, parentService: okhttp-scenario, traceId: not null} skipAnalysis: 'false' - segmentId: not null @@ -75,15 +75,15 @@ segmentItems: - {key: url, value: 'http://127.0.0.1:8080/okhttp-case/case/receiveContext-1'} - {key: http.method, value: GET} refs: - - {parentEndpoint: /okhttp-case/case/receiveContext-0, networkAddress: '127.0.0.1:8080', - refType: CrossProcess, parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not + - {parentEndpoint: Async/execute, networkAddress: '127.0.0.1:8080', + refType: CrossProcess, parentSpanId: 3, parentTraceSegmentId: not null, parentServiceInstance: not null, parentService: okhttp-scenario, traceId: not null} skipAnalysis: 'false' - segmentId: not null spans: - operationName: /okhttp-case/case/receiveContext-0 - parentSpanId: -1 - spanId: 0 + parentSpanId: 0 + spanId: 1 spanLayer: Http startTime: nq 0 endTime: nq 0 @@ -94,8 +94,37 @@ segmentItems: tags: - {key: http.method, value: GET} - {key: url, value: 'http://127.0.0.1:8080/okhttp-case/case/receiveContext-0'} - refs: - - {parentEndpoint: GET:/case/okhttp-case, networkAddress: '', refType: CrossThread, - parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not - null, parentService: okhttp-scenario, traceId: not null} skipAnalysis: 'false' + - operationName: /okhttp-case/case/receiveContext-1 + parentSpanId: 2 + spanId: 3 + spanLayer: Http + startTime: nq 0 + endTime: nq 0 + componentId: 12 + isError: false + spanType: Exit + peer: 127.0.0.1:8080 + skipAnalysis: false + tags: + - {key: http.method, value: GET} + - {key: url, value: 'http://127.0.0.1:8080/okhttp-case/case/receiveContext-1'} + - {operationName: Callback/onResponse, parentSpanId: 0, spanId: 2, + spanLayer: Unknown, startTime: nq 0, endTime: nq 0, componentId: 0, + isError: false, spanType: Local, peer: '', skipAnalysis: false} + - operationName: Async/execute + parentSpanId: -1 + spanId: 0 + spanLayer: Unknown + startTime: nq 0 + endTime: nq 0 + componentId: 0 + isError: false + spanType: Local + peer: '' + skipAnalysis: false + refs: + - {parentEndpoint: 'GET:/case/okhttp-case', networkAddress: '', refType: CrossThread, + parentSpanId: 1, parentTraceSegmentId: not null, + parentServiceInstance: not null, parentService: okhttp-scenario, + traceId: not null} diff --git a/test/plugin/scenarios/okhttp2-scenario/bin/startup.sh b/test/plugin/scenarios/okhttp2-scenario/bin/startup.sh new file mode 100644 index 0000000..6a7d3b6 --- /dev/null +++ b/test/plugin/scenarios/okhttp2-scenario/bin/startup.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +home="$(cd "$(dirname $0)"; pwd)" + +java -jar ${agent_opts} ${home}/../libs/okhttp2-scenario.jar & \ No newline at end of file diff --git a/test/plugin/scenarios/okhttp-scenario/config/expectedData.yaml b/test/plugin/scenarios/okhttp2-scenario/config/expectedData.yaml similarity index 52% copy from test/plugin/scenarios/okhttp-scenario/config/expectedData.yaml copy to test/plugin/scenarios/okhttp2-scenario/config/expectedData.yaml index fb12e4b..4ed87e8 100644 --- a/test/plugin/scenarios/okhttp-scenario/config/expectedData.yaml +++ b/test/plugin/scenarios/okhttp2-scenario/config/expectedData.yaml @@ -14,12 +14,12 @@ # See the License for the specific language governing permissions and # limitations under the License. segmentItems: -- serviceName: okhttp-scenario +- serviceName: okhttp2-scenario segmentSize: ge 5 segments: - segmentId: not null spans: - - operationName: Async/okhttp-case/case/receiveContext-0 + - operationName: Async/okhttp2-scenario/case/receiveContext-0 parentSpanId: 0 spanId: 1 startTime: nq 0 @@ -28,7 +28,7 @@ segmentItems: isError: false spanType: Local skipAnalysis: 'false' - - operationName: GET:/case/okhttp-case + - operationName: GET:/case/okhttp2-scenario parentSpanId: -1 spanId: 0 spanLayer: Http @@ -38,7 +38,7 @@ segmentItems: isError: false spanType: Entry tags: - - {key: url, value: 'http://localhost:8080/okhttp-case/case/okhttp-case'} + - {key: url, value: 'http://localhost:8080/okhttp2-scenario/case/okhttp2-scenario'} - {key: http.method, value: GET} skipAnalysis: 'false' - segmentId: not null @@ -53,12 +53,12 @@ segmentItems: isError: false spanType: Entry tags: - - {key: url, value: 'http://127.0.0.1:8080/okhttp-case/case/receiveContext-0'} + - {key: url, value: 'http://127.0.0.1:8080/okhttp2-scenario/case/receiveContext-0'} - {key: http.method, value: GET} refs: - - {parentEndpoint: /okhttp-case/case/receiveContext-0, networkAddress: '127.0.0.1:8080', - refType: CrossProcess, parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not - null, parentService: okhttp-scenario, traceId: not null} + - {parentEndpoint: Async/execute, networkAddress: '127.0.0.1:8080', + refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not + null, parentService: okhttp2-scenario, traceId: not null} skipAnalysis: 'false' - segmentId: not null spans: @@ -72,18 +72,18 @@ segmentItems: isError: false spanType: Entry tags: - - {key: url, value: 'http://127.0.0.1:8080/okhttp-case/case/receiveContext-1'} + - {key: url, value: 'http://127.0.0.1:8080/okhttp2-scenario/case/receiveContext-1'} - {key: http.method, value: GET} refs: - - {parentEndpoint: /okhttp-case/case/receiveContext-0, networkAddress: '127.0.0.1:8080', - refType: CrossProcess, parentSpanId: 0, parentTraceSegmentId: not null, parentServiceInstance: not - null, parentService: okhttp-scenario, traceId: not null} + - {parentEndpoint: Async/execute, networkAddress: '127.0.0.1:8080', + refType: CrossProcess, parentSpanId: 3, parentTraceSegmentId: not null, parentServiceInstance: not + null, parentService: okhttp2-scenario, traceId: not null} skipAnalysis: 'false' - segmentId: not null spans: - - operationName: /okhttp-case/case/receiveContext-0 - parentSpanId: -1 - spanId: 0 + - operationName: /okhttp2-scenario/case/receiveContext-0 + parentSpanId: 0 + spanId: 1 spanLayer: Http startTime: nq 0 endTime: nq 0 @@ -93,9 +93,38 @@ segmentItems: peer: 127.0.0.1:8080 tags: - {key: http.method, value: GET} - - {key: url, value: 'http://127.0.0.1:8080/okhttp-case/case/receiveContext-0'} + - {key: url, value: 'http://127.0.0.1:8080/okhttp2-scenario/case/receiveContext-0'} + - operationName: /okhttp2-scenario/case/receiveContext-1 + parentSpanId: 2 + spanId: 3 + spanLayer: Http + startTime: nq 0 + endTime: nq 0 + componentId: 12 + isError: false + spanType: Exit + peer: 127.0.0.1:8080 + skipAnalysis: false + tags: + - {key: http.method, value: GET} + - {key: url, value: 'http://127.0.0.1:8080/okhttp2-scenario/case/receiveContext-1'} + - {operationName: Callback/onResponse, parentSpanId: 0, spanId: 2, + spanLayer: Unknown, startTime: nq 0, endTime: nq 0, componentId: 0, + isError: false, spanType: Local, peer: '', skipAnalysis: false} + - operationName: Async/execute + operationId: 0 + parentSpanId: -1 + spanId: 0 + spanLayer: Unknown + startTime: nq 0 + endTime: nq 0 + componentId: 0 + isError: false + spanType: Local + peer: '' + skipAnalysis: false refs: - - {parentEndpoint: GET:/case/okhttp-case, networkAddress: '', refType: CrossThread, - parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not - null, parentService: okhttp-scenario, traceId: not null} - skipAnalysis: 'false' + - {parentEndpoint: 'GET:/case/okhttp2-scenario', networkAddress: '', refType: CrossThread, + parentSpanId: 1, parentTraceSegmentId: not null, + parentServiceInstance: not null, parentService: okhttp2-scenario, + traceId: not null} diff --git a/test/plugin/scenarios/okhttp2-scenario/configuration.yml b/test/plugin/scenarios/okhttp2-scenario/configuration.yml new file mode 100644 index 0000000..b350fc7 --- /dev/null +++ b/test/plugin/scenarios/okhttp2-scenario/configuration.yml @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +type: jvm +entryService: http://localhost:8080/okhttp2-scenario/case/okhttp2-scenario +healthCheck: http://localhost:8080/okhttp2-scenario/case/healthCheck +startScript: ./bin/startup.sh diff --git a/test/plugin/scenarios/okhttp2-scenario/pom.xml b/test/plugin/scenarios/okhttp2-scenario/pom.xml new file mode 100644 index 0000000..f572427 --- /dev/null +++ b/test/plugin/scenarios/okhttp2-scenario/pom.xml @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <groupId>org.apache.skywalking.apm.testcase</groupId> + <artifactId>okhttp2-scenario</artifactId> + <version>1.0.0</version> + <packaging>jar</packaging> + + <modelVersion>4.0.0</modelVersion> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <compiler.version>1.8</compiler.version> + <test.framework.version>2.7.5</test.framework.version> + <spring-boot-version>2.1.6.RELEASE</spring-boot-version> + <lombok.version>1.18.20</lombok.version> + </properties> + + <name>skywalking-okhttp2-scenario</name> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-dependencies</artifactId> + <version>${spring-boot-version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>com.squareup.okhttp</groupId> + <artifactId>okhttp</artifactId> + <version>${test.framework.version}</version> + </dependency> + + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + <exclusions> + <exclusion> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-logging</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-log4j2</artifactId> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> + + <build> + <finalName>okhttp2-scenario</finalName> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>${compiler.version}</source> + <target>${compiler.version}</target> + <encoding>${project.build.sourceEncoding}</encoding> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <executions> + <execution> + <id>assemble</id> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + <configuration> + <descriptors> + <descriptor>src/main/assembly/assembly.xml</descriptor> + </descriptors> + <outputDirectory>./target/</outputDirectory> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/test/plugin/scenarios/okhttp2-scenario/src/main/assembly/assembly.xml b/test/plugin/scenarios/okhttp2-scenario/src/main/assembly/assembly.xml new file mode 100644 index 0000000..e1f8765 --- /dev/null +++ b/test/plugin/scenarios/okhttp2-scenario/src/main/assembly/assembly.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ 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. + ~ + --> +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"> + <formats> + <format>zip</format> + </formats> + + <fileSets> + <fileSet> + <directory>./bin</directory> + <fileMode>0775</fileMode> + </fileSet> + </fileSets> + + <files> + <file> + <source>${project.build.directory}/okhttp2-scenario.jar</source> + <outputDirectory>./libs</outputDirectory> + <fileMode>0775</fileMode> + </file> + </files> +</assembly> diff --git a/test/plugin/scenarios/okhttp2-scenario/src/main/java/test/apache/skywalking/apm/testcase/okhttp2/Application.java b/test/plugin/scenarios/okhttp2-scenario/src/main/java/test/apache/skywalking/apm/testcase/okhttp2/Application.java new file mode 100644 index 0000000..0b4d8b6 --- /dev/null +++ b/test/plugin/scenarios/okhttp2-scenario/src/main/java/test/apache/skywalking/apm/testcase/okhttp2/Application.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package test.apache.skywalking.apm.testcase.okhttp2; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + try { + SpringApplication.run(Application.class, args); + } catch (Exception e) { + // Never do this + } + } +} diff --git a/test/plugin/scenarios/okhttp2-scenario/src/main/java/test/apache/skywalking/apm/testcase/okhttp2/controller/CaseController.java b/test/plugin/scenarios/okhttp2-scenario/src/main/java/test/apache/skywalking/apm/testcase/okhttp2/controller/CaseController.java new file mode 100644 index 0000000..60aa663 --- /dev/null +++ b/test/plugin/scenarios/okhttp2-scenario/src/main/java/test/apache/skywalking/apm/testcase/okhttp2/controller/CaseController.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 test.apache.skywalking.apm.testcase.okhttp2.controller; + +import com.squareup.okhttp.Callback; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; +import java.io.IOException; +import lombok.extern.log4j.Log4j2; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/case") +@Log4j2 +public class CaseController { + + private static final String SUCCESS = "Success"; + + @RequestMapping("/receiveContext-1") + @ResponseBody + public String receiveContextService1() throws InterruptedException { + return "receiveContext-1"; + } + + @RequestMapping("/receiveContext-0") + @ResponseBody + public String receiveContextService0() throws InterruptedException { + return "receiveContext-0"; + } + + @RequestMapping("/okhttp2-scenario") + @ResponseBody + public String okHttpScenario() { + // Like gateway forward trace header. + Request request = new Request.Builder().url("http://127.0.0.1:8080/okhttp2-scenario/case/receiveContext-0") + .build(); + + new OkHttpClient().newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Request request, IOException e) { + + } + + @Override + public void onResponse(Response response) throws IOException { + Request request = new Request.Builder().url( + "http://127.0.0.1:8080/okhttp2-scenario/case/receiveContext-1") + .build(); + new OkHttpClient().newCall(request).execute(); + } + + }); + + return "Success"; + } + + @RequestMapping("/healthCheck") + @ResponseBody + public String healthCheck() { + // your codes + return SUCCESS; + } + +} diff --git a/test/plugin/scenarios/okhttp2-scenario/src/main/resources/application.yaml b/test/plugin/scenarios/okhttp2-scenario/src/main/resources/application.yaml new file mode 100644 index 0000000..aeff4b1 --- /dev/null +++ b/test/plugin/scenarios/okhttp2-scenario/src/main/resources/application.yaml @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +server: + port: 8080 + servlet: + context-path: /okhttp2-scenario +logging: + config: classpath:log4j2.xml \ No newline at end of file diff --git a/test/plugin/scenarios/okhttp2-scenario/src/main/resources/log4j2.xml b/test/plugin/scenarios/okhttp2-scenario/src/main/resources/log4j2.xml new file mode 100644 index 0000000..9849ed5 --- /dev/null +++ b/test/plugin/scenarios/okhttp2-scenario/src/main/resources/log4j2.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ 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. + ~ + --> +<Configuration status="WARN"> + <Appenders> + <Console name="Console" target="SYSTEM_ERR"> + <PatternLayout charset="UTF-8" pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%p] - %l - %m%n"/> + </Console> + </Appenders> + <Loggers> + <Root level="WARN"> + <AppenderRef ref="Console"/> + </Root> + </Loggers> +</Configuration> \ No newline at end of file diff --git a/test/plugin/scenarios/okhttp2-scenario/support-version.list b/test/plugin/scenarios/okhttp2-scenario/support-version.list new file mode 100644 index 0000000..f758f52 --- /dev/null +++ b/test/plugin/scenarios/okhttp2-scenario/support-version.list @@ -0,0 +1,22 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# lists your version here (Contains only the last version number of each minor version.) + +2.4.0 +2.5.0 +2.6.0 +2.7.5 \ No newline at end of file