Create instrumentation-core apache-httpclient-4.0 (#694)

This commit is contained in:
Munir Abdinur 2020-07-16 23:00:26 -04:00 committed by GitHub
parent 10f24aff65
commit 3662cee7ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 187 additions and 100 deletions

View File

@ -0,0 +1,24 @@
plugins {
id "com.github.johnrengelman.shadow"
}
ext {
noShadowPublish = true
}
apply from: "$rootDir/gradle/java.gradle"
group = 'io.opentelemetry.instrumentation'
shadowJar {
archiveClassifier = 'agent'
configurations = []
relocate 'io.opentelemetry.instrumentation.apachehttpclient.v4_0', 'io.opentelemetry.auto.instrumentation.apachehttpclient.v4_0.shaded'
}
dependencies {
compileOnly project(':auto-bootstrap')
compileOnly deps.opentelemetryApi
compileOnly group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.0'
}

View File

@ -14,22 +14,25 @@
* limitations under the License.
*/
package io.opentelemetry.auto.instrumentation.apachehttpclient.v4_0;
package io.opentelemetry.instrumentation.apachehttpclient.v4_0;
import io.grpc.Context;
import io.opentelemetry.OpenTelemetry;
import io.opentelemetry.auto.bootstrap.instrumentation.decorator.HttpClientDecorator;
import io.opentelemetry.trace.Tracer;
import java.net.URI;
import org.apache.http.Header;
import org.apache.http.HttpMessage;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
public class ApacheHttpClientDecorator extends HttpClientDecorator<HttpUriRequest, HttpResponse> {
class ApacheHttpClientDecorator extends HttpClientDecorator<HttpUriRequest, HttpResponse> {
public static final ApacheHttpClientDecorator DECORATE = new ApacheHttpClientDecorator();
public static final Tracer TRACER =
OpenTelemetry.getTracerProvider().get("io.opentelemetry.auto.apache-httpclient-4.0");
public void inject(Context context, HttpUriRequest request) {
OpenTelemetry.getPropagators()
.getHttpTextFormat()
.inject(context, request, HttpHeadersInjectAdapter.SETTER);
}
@Override
protected String method(final HttpUriRequest httpRequest) {

View File

@ -0,0 +1,84 @@
/*
* 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.instrumentation.apachehttpclient.v4_0;
import static io.opentelemetry.context.ContextUtils.withScopedContext;
import static io.opentelemetry.instrumentation.apachehttpclient.v4_0.ApacheHttpClientDecorator.DECORATE;
import io.grpc.Context;
import io.opentelemetry.OpenTelemetry;
import io.opentelemetry.auto.bootstrap.CallDepthThreadLocalMap;
import io.opentelemetry.auto.bootstrap.instrumentation.decorator.ClientDecorator;
import io.opentelemetry.auto.instrumentation.api.SpanWithScope;
import io.opentelemetry.context.Scope;
import io.opentelemetry.trace.Span;
import io.opentelemetry.trace.Tracer;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
public class ApacheHttpClientHelper {
public static final Tracer TRACER =
OpenTelemetry.getTracerProvider().get("io.opentelemetry.auto.spring-webflux-5.0");
public static SpanWithScope doMethodEnter(final HttpUriRequest request) {
return doMethodEnter(request, TRACER);
}
public static SpanWithScope doMethodEnter(final HttpUriRequest request, final Tracer tracer) {
final Span span = DECORATE.getOrCreateSpan(request, tracer);
DECORATE.afterStart(span);
DECORATE.onRequest(span, request);
final Context context = ClientDecorator.currentContextWith(span);
if (span.getContext().isValid()) {
DECORATE.inject(context, request);
}
final Scope scope = withScopedContext(context);
return new SpanWithScope(span, scope);
}
public static void doMethodExitAndResetCallDepthThread(
final SpanWithScope spanWithScope, final Object result, final Throwable throwable) {
if (spanWithScope == null) {
return;
}
CallDepthThreadLocalMap.reset(HttpClient.class);
doMethodExit(spanWithScope, result, throwable);
}
public static void doMethodExit(
final SpanWithScope spanWithScope, final Object result, final Throwable throwable) {
try {
final Span span = spanWithScope.getSpan();
if (result instanceof HttpResponse) {
DECORATE.onResponse(span, (HttpResponse) result);
} // else they probably provided a ResponseHandler.
DECORATE.onError(span, throwable);
DECORATE.beforeFinish(span);
span.end();
} finally {
spanWithScope.closeScope();
}
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.opentelemetry.auto.instrumentation.apachehttpclient.v4_0;
package io.opentelemetry.instrumentation.apachehttpclient.v4_0;
import java.net.URI;
import java.net.URISyntaxException;

View File

@ -14,12 +14,12 @@
* limitations under the License.
*/
package io.opentelemetry.auto.instrumentation.apachehttpclient.v4_0;
package io.opentelemetry.instrumentation.apachehttpclient.v4_0;
import io.opentelemetry.context.propagation.HttpTextFormat;
import org.apache.http.client.methods.HttpUriRequest;
public class HttpHeadersInjectAdapter implements HttpTextFormat.Setter<HttpUriRequest> {
class HttpHeadersInjectAdapter implements HttpTextFormat.Setter<HttpUriRequest> {
public static final HttpHeadersInjectAdapter SETTER = new HttpHeadersInjectAdapter();

View File

@ -0,0 +1,44 @@
/*
* 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.instrumentation.apachehttpclient.v4_0;
import static io.opentelemetry.instrumentation.apachehttpclient.v4_0.ApacheHttpClientDecorator.DECORATE;
import io.opentelemetry.trace.Span;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
public class WrappingStatusSettingResponseHandler implements ResponseHandler {
final Span span;
final ResponseHandler handler;
public WrappingStatusSettingResponseHandler(final Span span, final ResponseHandler handler) {
this.span = span;
this.handler = handler;
}
@Override
public Object handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException {
if (null != span) {
DECORATE.onResponse(span, response);
}
return handler.handleResponse(response);
}
}

View File

@ -1,4 +1,4 @@
group = 'io.opentelemetry.instrumentation.spring'
group = 'io.opentelemetry.instrumentation'
apply plugin: 'java'
apply from: "$rootDir/gradle/java.gradle"

View File

@ -9,7 +9,7 @@ ext {
apply from: "$rootDir/gradle/java.gradle"
group = 'io.opentelemetry.instrumentation.spring.webflux'
group = 'io.opentelemetry.instrumentation'
dependencies {
compileOnly project(':auto-bootstrap')

View File

@ -1,4 +1,4 @@
group = 'io.opentelemetry.instrumentation.spring'
group = 'io.opentelemetry.instrumentation'
apply from: "$rootDir/gradle/java.gradle"

View File

@ -30,6 +30,7 @@ testSets {
}
dependencies {
implementation project(path: ':instrumentation-core:apache-httpclient-4.0', configuration: 'shadow')
compileOnly group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.0'
testImplementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.0'

View File

@ -16,12 +16,8 @@
package io.opentelemetry.auto.instrumentation.apachehttpclient.v4_0;
import static io.opentelemetry.auto.instrumentation.apachehttpclient.v4_0.ApacheHttpClientDecorator.DECORATE;
import static io.opentelemetry.auto.instrumentation.apachehttpclient.v4_0.ApacheHttpClientDecorator.TRACER;
import static io.opentelemetry.auto.instrumentation.apachehttpclient.v4_0.HttpHeadersInjectAdapter.SETTER;
import static io.opentelemetry.auto.tooling.ClassLoaderMatcher.hasClassesNamed;
import static io.opentelemetry.auto.tooling.bytebuddy.matcher.AgentElementMatchers.implementsInterface;
import static io.opentelemetry.context.ContextUtils.withScopedContext;
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
@ -30,15 +26,12 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
import com.google.auto.service.AutoService;
import io.grpc.Context;
import io.opentelemetry.OpenTelemetry;
import io.opentelemetry.auto.bootstrap.CallDepthThreadLocalMap;
import io.opentelemetry.auto.bootstrap.instrumentation.decorator.ClientDecorator;
import io.opentelemetry.auto.instrumentation.apachehttpclient.v4_0.shaded.ApacheHttpClientHelper;
import io.opentelemetry.auto.instrumentation.apachehttpclient.v4_0.shaded.HostAndRequestAsHttpUriRequest;
import io.opentelemetry.auto.instrumentation.apachehttpclient.v4_0.shaded.WrappingStatusSettingResponseHandler;
import io.opentelemetry.auto.instrumentation.api.SpanWithScope;
import io.opentelemetry.auto.tooling.Instrumenter;
import io.opentelemetry.context.Scope;
import io.opentelemetry.trace.Span;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import net.bytebuddy.asm.Advice;
@ -48,8 +41,6 @@ import net.bytebuddy.implementation.bytecode.assign.Assigner;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpUriRequest;
@ -75,11 +66,11 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
@Override
public String[] helperClassNames() {
return new String[] {
packageName + ".ApacheHttpClientDecorator",
packageName + ".HttpHeadersInjectAdapter",
packageName + ".HostAndRequestAsHttpUriRequest",
getClass().getName() + "$HelperMethods",
getClass().getName() + "$WrappingStatusSettingResponseHandler",
packageName + ".shaded.ApacheHttpClientDecorator",
packageName + ".shaded.HttpHeadersInjectAdapter",
packageName + ".shaded.HostAndRequestAsHttpUriRequest",
packageName + ".shaded.ApacheHttpClientHelper",
packageName + ".shaded.WrappingStatusSettingResponseHandler",
};
}
@ -170,45 +161,6 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
return transformers;
}
public static class HelperMethods {
public static SpanWithScope doMethodEnter(final HttpUriRequest request) {
final Span span = DECORATE.getOrCreateSpan(request, TRACER);
DECORATE.afterStart(span);
DECORATE.onRequest(span, request);
final Context context = ClientDecorator.currentContextWith(span);
if (span.getContext().isValid()) {
OpenTelemetry.getPropagators().getHttpTextFormat().inject(context, request, SETTER);
}
final Scope scope = withScopedContext(context);
return new SpanWithScope(span, scope);
}
public static void doMethodExit(
final SpanWithScope spanWithScope, final Object result, final Throwable throwable) {
if (spanWithScope == null) {
return;
}
CallDepthThreadLocalMap.reset(HttpClient.class);
try {
final Span span = spanWithScope.getSpan();
if (result instanceof HttpResponse) {
DECORATE.onResponse(span, (HttpResponse) result);
} // else they probably provided a ResponseHandler.
DECORATE.onError(span, throwable);
DECORATE.beforeFinish(span);
span.end();
} finally {
spanWithScope.closeScope();
}
}
}
public static class UriRequestAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static SpanWithScope methodEnter(@Advice.Argument(0) final HttpUriRequest request) {
@ -217,7 +169,7 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
return null;
}
return HelperMethods.doMethodEnter(request);
return ApacheHttpClientHelper.doMethodEnter(request);
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
@ -225,8 +177,7 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
@Advice.Enter final SpanWithScope spanWithScope,
@Advice.Return final Object result,
@Advice.Thrown final Throwable throwable) {
HelperMethods.doMethodExit(spanWithScope, result, throwable);
ApacheHttpClientHelper.doMethodExitAndResetCallDepthThread(spanWithScope, result, throwable);
}
}
@ -246,7 +197,7 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
return null;
}
final SpanWithScope spanWithScope = HelperMethods.doMethodEnter(request);
final SpanWithScope spanWithScope = ApacheHttpClientHelper.doMethodEnter(request);
// Wrap the handler so we capture the status code
if (handler instanceof ResponseHandler) {
@ -262,8 +213,7 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
@Advice.Enter final SpanWithScope spanWithScope,
@Advice.Return final Object result,
@Advice.Thrown final Throwable throwable) {
HelperMethods.doMethodExit(spanWithScope, result, throwable);
ApacheHttpClientHelper.doMethodExitAndResetCallDepthThread(spanWithScope, result, throwable);
}
}
@ -277,9 +227,10 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
}
if (request instanceof HttpUriRequest) {
return HelperMethods.doMethodEnter((HttpUriRequest) request);
return ApacheHttpClientHelper.doMethodEnter((HttpUriRequest) request);
} else {
return HelperMethods.doMethodEnter(new HostAndRequestAsHttpUriRequest(host, request));
return ApacheHttpClientHelper.doMethodEnter(
new HostAndRequestAsHttpUriRequest(host, request));
}
}
@ -288,8 +239,7 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
@Advice.Enter final SpanWithScope spanWithScope,
@Advice.Return final Object result,
@Advice.Thrown final Throwable throwable) {
HelperMethods.doMethodExit(spanWithScope, result, throwable);
ApacheHttpClientHelper.doMethodExitAndResetCallDepthThread(spanWithScope, result, throwable);
}
}
@ -313,10 +263,10 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
final SpanWithScope spanWithScope;
if (request instanceof HttpUriRequest) {
spanWithScope = HelperMethods.doMethodEnter((HttpUriRequest) request);
spanWithScope = ApacheHttpClientHelper.doMethodEnter((HttpUriRequest) request);
} else {
spanWithScope =
HelperMethods.doMethodEnter(new HostAndRequestAsHttpUriRequest(host, request));
ApacheHttpClientHelper.doMethodEnter(new HostAndRequestAsHttpUriRequest(host, request));
}
// Wrap the handler so we capture the status code
@ -333,27 +283,7 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default {
@Advice.Enter final SpanWithScope spanWithScope,
@Advice.Return final Object result,
@Advice.Thrown final Throwable throwable) {
HelperMethods.doMethodExit(spanWithScope, result, throwable);
}
}
public static class WrappingStatusSettingResponseHandler implements ResponseHandler {
final Span span;
final ResponseHandler handler;
public WrappingStatusSettingResponseHandler(final Span span, final ResponseHandler handler) {
this.span = span;
this.handler = handler;
}
@Override
public Object handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException {
if (null != span) {
DECORATE.onResponse(span, response);
}
return handler.handleResponse(response);
ApacheHttpClientHelper.doMethodExitAndResetCallDepthThread(spanWithScope, result, throwable);
}
}
}

View File

@ -150,6 +150,7 @@ include ':instrumentation:twilio-6.6'
include ':instrumentation:vertx-3.0'
include ':instrumentation:vertx-reactive-3.5'
include ':instrumentation-core:apache-httpclient-4.0'
include ':instrumentation-core:aws-sdk:aws-sdk-2.2'
include ':instrumentation-core:reactor-3.1'
include ':instrumentation-core:servlet'