diff --git a/.github/workflows/plugins-test.2.yaml b/.github/workflows/plugins-test.2.yaml
index 2ded7f693..44489ee91 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 6218db077..46455b027 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 000000000..be93a8ada
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/pom.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+ apm-sdk-plugin
+ org.apache.skywalking
+ 8.8.0-SNAPSHOT
+
+ 4.0.0
+
+ okhttp-2.x-plugin
+ okhttp-2.x-plugin
+ jar
+
+
+ 2.7.5
+
+
+
+
+ com.squareup.okhttp
+ okhttp
+ ${okhttp.version}
+ provided
+
+
+ org.apache.skywalking
+ apm-okhttp-common
+ ${project.version}
+ provided
+
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/AsyncCallInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/AsyncCallInterceptor.java
new file mode 100644
index 000000000..2163ec1e9
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/AsyncCallInterceptor.java
@@ -0,0 +1,70 @@
+/*
+ * 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 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 org.apache.skywalking.apm.plugin.okhttp.common.EnhanceRequiredInfo;
+
+/**
+ * {@link AsyncCallInterceptor} get the `EnhanceRequiredInfo` instance from `SkyWalkingDynamicField` and then put it
+ * into `AsyncCall` instance when the `AsyncCall` constructor called.
+ *
+ * {@link AsyncCallInterceptor} also create an exit span by using the `EnhanceRequiredInfo` when the `execute` method
+ * called.
+ */
+public class AsyncCallInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ /**
+ * The first argument of constructor is not the `real` parameter when the enhance class is an inner class. This
+ * is the JDK compiler mechanism.
+ */
+ EnhancedInstance realCallInstance = (EnhancedInstance) allArguments[1];
+ Object enhanceRequireInfo = realCallInstance.getSkyWalkingDynamicField();
+
+ objInst.setSkyWalkingDynamicField(enhanceRequireInfo);
+ }
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ EnhanceRequiredInfo enhanceRequiredInfo = (EnhanceRequiredInfo) objInst.getSkyWalkingDynamicField();
+ ContextManager.createLocalSpan("Async/execute");
+ ContextManager.continued(enhanceRequiredInfo.getContextSnapshot());
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().log(t);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/CallInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/CallInterceptor.java
new file mode 100644
index 000000000..adf5965ee
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/CallInterceptor.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.okhttp.v2;
+
+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.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+public class CallInterceptor implements 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 beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ Request request = (Request) objInst.getSkyWalkingDynamicField();
+ HttpUrl requestUrl = request.httpUrl();
+ AbstractSpan span = ContextManager.createExitSpan(requestUrl.uri()
+ .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();
+ 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 {
+ Response response = (Response) ret;
+ if (response != null) {
+ int statusCode = response.code();
+ AbstractSpan span = ContextManager.activeSpan();
+ if (statusCode >= 400) {
+ span.errorOccurred();
+ 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) {
+ ContextManager.activeSpan().log(t);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/EnqueueInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/EnqueueInterceptor.java
new file mode 100644
index 000000000..a487a3d25
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/EnqueueInterceptor.java
@@ -0,0 +1,73 @@
+/*
+ * 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 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 org.apache.skywalking.apm.plugin.okhttp.common.EnhanceRequiredInfo;
+
+/**
+ * {@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 EnqueueInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ 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.
+ */
+
+ 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;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ 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-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/OnResponseInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/OnResponseInterceptor.java
new file mode 100644
index 000000000..b4b540cb9
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/OnResponseInterceptor.java
@@ -0,0 +1,51 @@
+/*
+ * 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 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;
+
+/**
+ * {@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 {
+ ContextManager.createLocalSpan("Callback/onResponse");
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().log(t);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/RealCallInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/RealCallInterceptor.java
new file mode 100644
index 000000000..2b9387e57
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/okhttp-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/okhttp/v2/RealCallInterceptor.java
@@ -0,0 +1,128 @@
+/*
+ * 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 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;
+
+/**
+ * {@link RealCallInterceptor} intercept the synchronous http calls by the discovery of okhttp.
+ */
+public class RealCallInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
+
+ 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");
+ field.setAccessible(true);
+ FIELD_HEADERS_OF_REQUEST = field;
+ } catch (Exception ignore) {
+ FIELD_HEADERS_OF_REQUEST = null;
+ }
+ }
+
+ @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 {
+ Request request = (Request) objInst.getSkyWalkingDynamicField();
+
+ ContextCarrier contextCarrier = new ContextCarrier();
+ 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());
+ 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());
+ }
+ }
+
+ /**
+ * 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 {
+ Response response = (Response) ret;
+ if (response != null) {
+ int statusCode = response.code();
+ AbstractSpan span = ContextManager.activeSpan();
+ if (statusCode >= 400) {
+ span.errorOccurred();
+ 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);
+ }
+}
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 000000000..3daa03d3d
--- /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 getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPT_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher 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 000000000..dd65eb037
--- /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 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 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 000000000..aee7fcf90
--- /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 getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPT_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("execute");
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return INTERCEPT_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher 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 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 000000000..d3772e81e
--- /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 000000000..692753f54
--- /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 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 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 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 0658359b3..97465453f 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 getConstructorMatcher() {
- return any();
- }
+ return new ConstructorInterceptPoint[]{
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher 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 getMethodsMatcher() {
- return named("execute");
- }
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher 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 getMethodsMatcher() {
- return named("enqueue").and(takesArguments(1));
- }
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher 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;
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher 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;
+ }
}
- }
};
}
}
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 ea97358b1..1f7edc8b7 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 getConstructorMatcher() {
- return any();
- }
+ return new ConstructorInterceptPoint[]{
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher 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 getMethodsMatcher() {
- return named("execute");
- }
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher 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 getMethodsMatcher() {
- return named("enqueue").and(takesArguments(1));
- }
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher 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;
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher 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;
+ }
}
- }
};
}
}
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 54364f469..20e966e81 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/CallInterceptor.java b/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/CallInterceptor.java
new file mode 100644
index 000000000..90b15a405
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/okhttp-common/src/main/java/org/apache/skywalking/apm/plugin/okhttp/common/CallInterceptor.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.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;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+public class CallInterceptor implements 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 beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ Request request = (Request) objInst.getSkyWalkingDynamicField();
+ HttpUrl requestUrl = request.url();
+ AbstractSpan span = ContextManager.createExitSpan(requestUrl.uri()
+ .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();
+ 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 {
+ Response response = (Response) ret;
+ if (response != null) {
+ int statusCode = response.code();
+ AbstractSpan span = ContextManager.activeSpan();
+ if (statusCode >= 400) {
+ span.errorOccurred();
+ 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) {
+ 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 8b38b4c8d..7a75f9d29 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 62728b364..b1bd3c1fe 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 c94464953..c305c556b 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 dfafd196f..b33edaca1 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -112,6 +112,7 @@
httpclient-5.x-pluginclickhouse-0.3.x-pluginkylin-jdbc-2.6.x-3.x-4.x-plugin
+ okhttp-2.x-pluginpom
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 e3aa29bd8..968b96869 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 98d49a9d9..9f5c98052 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 f90d4afd6..e7249bdbf 100755
--- a/pom.xml
+++ b/pom.xml
@@ -391,6 +391,7 @@
${project.build.sourceDirectory}${project.build.testSourceDirectory}
+scenarios/okhttp-scenario
**/*.properties,
diff --git a/test/plugin/scenarios/okhttp-scenario/config/expectedData.yaml b/test/plugin/scenarios/okhttp-scenario/config/expectedData.yaml
index fb12e4b3d..640777184 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 000000000..6a7d3b60f
--- /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/okhttp2-scenario/config/expectedData.yaml b/test/plugin/scenarios/okhttp2-scenario/config/expectedData.yaml
new file mode 100644
index 000000000..4ed87e874
--- /dev/null
+++ b/test/plugin/scenarios/okhttp2-scenario/config/expectedData.yaml
@@ -0,0 +1,130 @@
+# 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.
+segmentItems:
+- serviceName: okhttp2-scenario
+ segmentSize: ge 5
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: Async/okhttp2-scenario/case/receiveContext-0
+ parentSpanId: 0
+ spanId: 1
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 0
+ isError: false
+ spanType: Local
+ skipAnalysis: 'false'
+ - operationName: GET:/case/okhttp2-scenario
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ isError: false
+ spanType: Entry
+ tags:
+ - {key: url, value: 'http://localhost:8080/okhttp2-scenario/case/okhttp2-scenario'}
+ - {key: http.method, value: GET}
+ skipAnalysis: 'false'
+ - segmentId: not null
+ spans:
+ - operationName: GET:/case/receiveContext-0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ isError: false
+ spanType: Entry
+ tags:
+ - {key: url, value: 'http://127.0.0.1:8080/okhttp2-scenario/case/receiveContext-0'}
+ - {key: http.method, value: GET}
+ refs:
+ - {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:
+ - operationName: GET:/case/receiveContext-1
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 14
+ isError: false
+ spanType: Entry
+ tags:
+ - {key: url, value: 'http://127.0.0.1:8080/okhttp2-scenario/case/receiveContext-1'}
+ - {key: http.method, value: GET}
+ refs:
+ - {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: /okhttp2-scenario/case/receiveContext-0
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Http
+ startTime: nq 0
+ endTime: nq 0
+ componentId: 12
+ isError: false
+ spanType: Exit
+ peer: 127.0.0.1:8080
+ tags:
+ - {key: http.method, value: GET}
+ - {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/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 000000000..b350fc776
--- /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 000000000..f57242753
--- /dev/null
+++ b/test/plugin/scenarios/okhttp2-scenario/pom.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ org.apache.skywalking.apm.testcase
+ okhttp2-scenario
+ 1.0.0
+ jar
+
+ 4.0.0
+
+
+ UTF-8
+ 1.8
+ 2.7.5
+ 2.1.6.RELEASE
+ 1.18.20
+
+
+ skywalking-okhttp2-scenario
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot-version}
+ pom
+ import
+
+
+
+
+
+
+ com.squareup.okhttp
+ okhttp
+ ${test.framework.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-log4j2
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ provided
+
+
+
+
+ okhttp2-scenario
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+
+
+ maven-compiler-plugin
+
+ ${compiler.version}
+ ${compiler.version}
+ ${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ assemble
+ package
+
+ single
+
+
+
+ src/main/assembly/assembly.xml
+
+ ./target/
+
+
+
+
+
+
+
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 000000000..e1f876557
--- /dev/null
+++ b/test/plugin/scenarios/okhttp2-scenario/src/main/assembly/assembly.xml
@@ -0,0 +1,41 @@
+
+
+
+
+ zip
+
+
+
+
+ ./bin
+ 0775
+
+
+
+
+
+ ${project.build.directory}/okhttp2-scenario.jar
+ ./libs
+ 0775
+
+
+
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 000000000..0b4d8b6be
--- /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 000000000..60aa663de
--- /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 000000000..aeff4b1af
--- /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 000000000..9849ed5a8
--- /dev/null
+++ b/test/plugin/scenarios/okhttp2-scenario/src/main/resources/log4j2.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 000000000..f758f52ff
--- /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