Add instrumentation for okhttp 2.2+ (DataDog/dd-trace-java#1402)
This commit is contained in:
parent
c63b4fd9a3
commit
5ecd8cb81e
|
@ -6,7 +6,7 @@ spotless {
|
|||
target 'src/**/*.java'
|
||||
}
|
||||
groovy {
|
||||
licenseHeaderFile rootProject.file('gradle/enforcement/spotless.license.java'), '(package|import|public)'
|
||||
licenseHeaderFile rootProject.file('gradle/enforcement/spotless.license.java'), '(package|import|class)'
|
||||
}
|
||||
scala {
|
||||
licenseHeaderFile rootProject.file('gradle/enforcement/spotless.license.java'), '(package|import|public)'
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
apply from: "${rootDir}/gradle/instrumentation.gradle"
|
||||
apply plugin: 'org.unbroken-dome.test-sets'
|
||||
|
||||
/*
|
||||
Note: The Interceptor class for OkHttp was not introduced until 2.2+, so we need to make sure the
|
||||
instrumentation is not loaded unless the dependency is 2.2+.
|
||||
*/
|
||||
muzzle {
|
||||
pass {
|
||||
group = "com.squareup.okhttp"
|
||||
module = "okhttp"
|
||||
versions = "[2.2,3)"
|
||||
assertInverse = true
|
||||
}
|
||||
}
|
||||
|
||||
testSets {
|
||||
latestDepTest {
|
||||
dirName = 'test'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(group: 'com.squareup.okhttp', name: 'okhttp', version: '2.2.0')
|
||||
|
||||
compile project(':auto-tooling')
|
||||
|
||||
testCompile project(':testing')
|
||||
testCompile project(':instrumentation:java-concurrent')
|
||||
testCompile group: 'com.squareup.okhttp', name: 'okhttp', version: '2.2.0'
|
||||
|
||||
latestDepTestCompile group: 'com.squareup.okhttp', name: 'okhttp', version: '[2.6,3)'
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* Licensed 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 io.opentelemetry.auto.instrumentation.okhttp.v2_2;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.squareup.okhttp.Interceptor;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import io.opentelemetry.auto.tooling.Instrumenter;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
@AutoService(Instrumenter.class)
|
||||
public class OkHttp2Instrumentation extends Instrumenter.Default {
|
||||
public OkHttp2Instrumentation() {
|
||||
super("okhttp", "okhttp-2");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<? super TypeDescription> typeMatcher() {
|
||||
return named("com.squareup.okhttp.OkHttpClient");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] helperClassNames() {
|
||||
return new String[] {
|
||||
packageName + ".RequestBuilderInjectAdapter",
|
||||
packageName + ".OkHttpClientDecorator",
|
||||
packageName + ".TracingInterceptor",
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
||||
return Collections.singletonMap(
|
||||
isConstructor(), OkHttp2Instrumentation.class.getName() + "$OkHttp2ClientAdvice");
|
||||
}
|
||||
|
||||
public static class OkHttp2ClientAdvice {
|
||||
@Advice.OnMethodExit
|
||||
public static void addTracingInterceptor(@Advice.This final OkHttpClient client) {
|
||||
for (final Interceptor interceptor : client.interceptors()) {
|
||||
if (interceptor instanceof TracingInterceptor) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
client.interceptors().add(new TracingInterceptor());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* Licensed 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 io.opentelemetry.auto.instrumentation.okhttp.v2_2;
|
||||
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import io.opentelemetry.OpenTelemetry;
|
||||
import io.opentelemetry.auto.bootstrap.instrumentation.decorator.HttpClientDecorator;
|
||||
import io.opentelemetry.trace.Tracer;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
public class OkHttpClientDecorator extends HttpClientDecorator<Request, Response> {
|
||||
public static final OkHttpClientDecorator DECORATE = new OkHttpClientDecorator();
|
||||
|
||||
public static final Tracer TRACER =
|
||||
OpenTelemetry.getTracerProvider().get("io.opentelemetry.auto.okhttp-2.2");
|
||||
|
||||
@Override
|
||||
protected String method(final Request request) {
|
||||
return request.method();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URI url(final Request request) throws URISyntaxException {
|
||||
return request.url().toURI();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer status(final Response response) {
|
||||
return response.code();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* Licensed 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 io.opentelemetry.auto.instrumentation.okhttp.v2_2;
|
||||
|
||||
import com.squareup.okhttp.Request;
|
||||
import io.opentelemetry.context.propagation.HttpTextFormat;
|
||||
|
||||
public class RequestBuilderInjectAdapter implements HttpTextFormat.Setter<Request.Builder> {
|
||||
public static final RequestBuilderInjectAdapter SETTER = new RequestBuilderInjectAdapter();
|
||||
|
||||
@Override
|
||||
public void set(final Request.Builder carrier, final String key, final String value) {
|
||||
carrier.addHeader(key, value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* Licensed 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 io.opentelemetry.auto.instrumentation.okhttp.v2_2;
|
||||
|
||||
import static io.opentelemetry.auto.instrumentation.okhttp.v2_2.OkHttpClientDecorator.DECORATE;
|
||||
import static io.opentelemetry.auto.instrumentation.okhttp.v2_2.OkHttpClientDecorator.TRACER;
|
||||
import static io.opentelemetry.context.ContextUtils.withScopedContext;
|
||||
import static io.opentelemetry.trace.Span.Kind.CLIENT;
|
||||
import static io.opentelemetry.trace.TracingContextUtils.withSpan;
|
||||
|
||||
import com.squareup.okhttp.Interceptor;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import io.grpc.Context;
|
||||
import io.opentelemetry.OpenTelemetry;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.trace.Span;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TracingInterceptor implements Interceptor {
|
||||
@Override
|
||||
public Response intercept(final Chain chain) throws IOException {
|
||||
final Span span =
|
||||
TRACER
|
||||
.spanBuilder(DECORATE.spanNameForRequest(chain.request()))
|
||||
.setSpanKind(CLIENT)
|
||||
.startSpan();
|
||||
|
||||
DECORATE.afterStart(span);
|
||||
DECORATE.onRequest(span, chain.request());
|
||||
|
||||
final Context context = withSpan(span, Context.current());
|
||||
|
||||
final Request.Builder requestBuilder = chain.request().newBuilder();
|
||||
OpenTelemetry.getPropagators()
|
||||
.getHttpTextFormat()
|
||||
.inject(context, requestBuilder, RequestBuilderInjectAdapter.SETTER);
|
||||
|
||||
final Response response;
|
||||
try (final Scope scope = withScopedContext(context)) {
|
||||
response = chain.proceed(requestBuilder.build());
|
||||
} catch (final Exception e) {
|
||||
DECORATE.onError(span, e);
|
||||
span.end();
|
||||
throw e;
|
||||
}
|
||||
DECORATE.onResponse(span, response);
|
||||
DECORATE.beforeFinish(span);
|
||||
span.end();
|
||||
return response;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
class HeadersUtil {
|
||||
static headersToArray(Map<String, String> headers) {
|
||||
String[] headersArr = new String[headers.size() * 2]
|
||||
headers.eachWithIndex { k, v, i ->
|
||||
headersArr[i] = k
|
||||
headersArr[i + 1] = v
|
||||
}
|
||||
|
||||
headersArr
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
import com.squareup.okhttp.Callback
|
||||
import com.squareup.okhttp.Headers
|
||||
import com.squareup.okhttp.MediaType
|
||||
import com.squareup.okhttp.Request
|
||||
import com.squareup.okhttp.RequestBody
|
||||
import com.squareup.okhttp.Response
|
||||
import com.squareup.okhttp.internal.http.HttpMethod
|
||||
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS
|
||||
|
||||
class OkHttp2AsyncTest extends OkHttp2Test {
|
||||
@Override
|
||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||
def body = HttpMethod.requiresRequestBody(method) ? RequestBody.create(MediaType.parse("text/plain"), "") : null
|
||||
def request = new Request.Builder()
|
||||
.url(uri.toURL())
|
||||
.method(method, body)
|
||||
.headers(Headers.of(HeadersUtil.headersToArray(headers)))
|
||||
.build()
|
||||
|
||||
AtomicReference<Response> responseRef = new AtomicReference()
|
||||
AtomicReference<Exception> exRef = new AtomicReference()
|
||||
def latch = new CountDownLatch(1)
|
||||
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
void onResponse(Response response) {
|
||||
responseRef.set(response)
|
||||
callback?.call()
|
||||
latch.countDown()
|
||||
}
|
||||
|
||||
void onFailure(Request req, IOException e) {
|
||||
exRef.set(e)
|
||||
latch.countDown()
|
||||
}
|
||||
})
|
||||
latch.await(10, SECONDS)
|
||||
if (exRef.get() != null) {
|
||||
throw exRef.get()
|
||||
}
|
||||
return responseRef.get().code()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
import com.squareup.okhttp.Headers
|
||||
import com.squareup.okhttp.MediaType
|
||||
import com.squareup.okhttp.OkHttpClient
|
||||
import com.squareup.okhttp.Request
|
||||
import com.squareup.okhttp.RequestBody
|
||||
import com.squareup.okhttp.internal.http.HttpMethod
|
||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Timeout(5)
|
||||
class OkHttp2Test extends HttpClientTest {
|
||||
@Shared
|
||||
def client = new OkHttpClient()
|
||||
|
||||
def setupSpec() {
|
||||
client.setConnectTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
client.setReadTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
client.setWriteTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
}
|
||||
|
||||
@Override
|
||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||
def body = HttpMethod.requiresRequestBody(method) ? RequestBody.create(MediaType.parse("text/plain"), "") : null
|
||||
|
||||
def request = new Request.Builder()
|
||||
.url(uri.toURL())
|
||||
.method(method, body)
|
||||
.headers(Headers.of(HeadersUtil.headersToArray(headers)))
|
||||
.build()
|
||||
def response = client.newCall(request).execute()
|
||||
callback?.call()
|
||||
return response.code()
|
||||
}
|
||||
|
||||
boolean testRedirects() {
|
||||
false
|
||||
}
|
||||
}
|
|
@ -28,16 +28,12 @@ not transitive.
|
|||
dependencies {
|
||||
compileOnly(group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.0.0')
|
||||
|
||||
compile(project(':auto-tooling')) {
|
||||
exclude module: 'okhttp'
|
||||
}
|
||||
compile project(':auto-tooling')
|
||||
|
||||
testCompile(project(':testing')) {
|
||||
exclude module: 'okhttp'
|
||||
}
|
||||
testCompile(project(':instrumentation:java-concurrent')) {
|
||||
exclude module: 'okhttp'
|
||||
}
|
||||
testCompile project(':instrumentation:java-concurrent')
|
||||
testCompile group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.0.0'
|
||||
|
||||
// 4.x.x-alpha has been released and it looks like there are lots of incompatible changes
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.opentelemetry.auto.instrumentation.okhttp;
|
||||
package io.opentelemetry.auto.instrumentation.okhttp.v3_0;
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
|
|
@ -13,9 +13,11 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.opentelemetry.auto.instrumentation.okhttp;
|
||||
package io.opentelemetry.auto.instrumentation.okhttp.v3_0;
|
||||
|
||||
import io.opentelemetry.OpenTelemetry;
|
||||
import io.opentelemetry.auto.bootstrap.instrumentation.decorator.HttpClientDecorator;
|
||||
import io.opentelemetry.trace.Tracer;
|
||||
import java.net.URI;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
@ -23,6 +25,9 @@ import okhttp3.Response;
|
|||
public class OkHttpClientDecorator extends HttpClientDecorator<Request, Response> {
|
||||
public static final OkHttpClientDecorator DECORATE = new OkHttpClientDecorator();
|
||||
|
||||
public static final Tracer TRACER =
|
||||
OpenTelemetry.getTracerProvider().get("io.opentelemetry.auto.okhttp-3.0");
|
||||
|
||||
@Override
|
||||
protected String method(final Request httpRequest) {
|
||||
return httpRequest.method();
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.opentelemetry.auto.instrumentation.okhttp;
|
||||
package io.opentelemetry.auto.instrumentation.okhttp.v3_0;
|
||||
|
||||
import io.opentelemetry.context.propagation.HttpTextFormat;
|
||||
import okhttp3.Request;
|
|
@ -13,10 +13,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.opentelemetry.auto.instrumentation.okhttp;
|
||||
package io.opentelemetry.auto.instrumentation.okhttp.v3_0;
|
||||
|
||||
import static io.opentelemetry.auto.instrumentation.okhttp.OkHttpClientDecorator.DECORATE;
|
||||
import static io.opentelemetry.auto.instrumentation.okhttp.RequestBuilderInjectAdapter.SETTER;
|
||||
import static io.opentelemetry.auto.instrumentation.okhttp.v3_0.OkHttpClientDecorator.DECORATE;
|
||||
import static io.opentelemetry.auto.instrumentation.okhttp.v3_0.OkHttpClientDecorator.TRACER;
|
||||
import static io.opentelemetry.context.ContextUtils.withScopedContext;
|
||||
import static io.opentelemetry.trace.Span.Kind.CLIENT;
|
||||
import static io.opentelemetry.trace.TracingContextUtils.withSpan;
|
||||
|
@ -25,7 +25,6 @@ import io.grpc.Context;
|
|||
import io.opentelemetry.OpenTelemetry;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.trace.Span;
|
||||
import io.opentelemetry.trace.Tracer;
|
||||
import java.io.IOException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.Interceptor;
|
||||
|
@ -34,8 +33,6 @@ import okhttp3.Response;
|
|||
|
||||
@Slf4j
|
||||
public class TracingInterceptor implements Interceptor {
|
||||
public static final Tracer TRACER =
|
||||
OpenTelemetry.getTracerProvider().get("io.opentelemetry.auto.okhttp-3.0");
|
||||
|
||||
@Override
|
||||
public Response intercept(final Chain chain) throws IOException {
|
||||
|
@ -51,7 +48,9 @@ public class TracingInterceptor implements Interceptor {
|
|||
final Context context = withSpan(span, Context.current());
|
||||
|
||||
final Request.Builder requestBuilder = chain.request().newBuilder();
|
||||
OpenTelemetry.getPropagators().getHttpTextFormat().inject(context, requestBuilder, SETTER);
|
||||
OpenTelemetry.getPropagators()
|
||||
.getHttpTextFormat()
|
||||
.inject(context, requestBuilder, RequestBuilderInjectAdapter.SETTER);
|
||||
|
||||
final Response response;
|
||||
try (final Scope scope = withScopedContext(context)) {
|
|
@ -111,7 +111,8 @@ include ':instrumentation:mongo:mongo-common'
|
|||
include ':instrumentation:netty:netty-3.8'
|
||||
include ':instrumentation:netty:netty-4.0'
|
||||
include ':instrumentation:netty:netty-4.1'
|
||||
include ':instrumentation:okhttp-3.0'
|
||||
include ':instrumentation:okhttp:okhttp-2.2'
|
||||
include ':instrumentation:okhttp:okhttp-3.0'
|
||||
include ':instrumentation:opentelemetry-api-0.4'
|
||||
include ':instrumentation:play:play-2.3'
|
||||
include ':instrumentation:play:play-2.4'
|
||||
|
|
Loading…
Reference in New Issue