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

Reply via email to