diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientHelper.java b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientHelper.java index 7649f29c5d..89ed812e20 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientHelper.java +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientHelper.java @@ -5,18 +5,20 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0; -import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0.ApacheHttpClientTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0.ApacheHttpClientInstrumenters.instrumenter; import io.opentelemetry.context.Context; import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpUriRequest; -public class ApacheHttpClientHelper { +public final class ApacheHttpClientHelper { - public static void doMethodExit(Context context, Object result, Throwable throwable) { + public static void doMethodExit( + Context context, HttpUriRequest request, Object result, Throwable throwable) { if (throwable != null) { - tracer().endExceptionally(context, throwable); + instrumenter().end(context, request, null, throwable); } else if (result instanceof HttpResponse) { - tracer().end(context, (HttpResponse) result); + instrumenter().end(context, request, (HttpResponse) result, null); } else { // ended in WrappingStatusSettingResponseHandler } diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientHttpAttributesExtractor.java b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientHttpAttributesExtractor.java new file mode 100644 index 0000000000..64a2277fb2 --- /dev/null +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientHttpAttributesExtractor.java @@ -0,0 +1,144 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0; + +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpAttributesExtractor; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import java.net.URI; +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.methods.HttpUriRequest; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class ApacheHttpClientHttpAttributesExtractor + extends HttpAttributesExtractor { + + private static final Logger logger = + LoggerFactory.getLogger(ApacheHttpClientHttpAttributesExtractor.class); + + @Override + protected String method(HttpUriRequest request) { + return request.getMethod(); + } + + @Override + protected String url(HttpUriRequest request) { + return request.getURI().toString(); + } + + @Override + protected String target(HttpUriRequest request) { + URI uri = request.getURI(); + String pathString = uri.getPath(); + String queryString = uri.getQuery(); + if (pathString != null && queryString != null) { + return pathString + "?" + queryString; + } else if (queryString != null) { + return "?" + queryString; + } else { + return pathString; + } + } + + @Override + @Nullable + protected String host(HttpUriRequest request) { + Header header = request.getFirstHeader("Host"); + if (header != null) { + return header.getValue(); + } + return null; + } + + @Override + @Nullable + protected String scheme(HttpUriRequest request) { + return request.getURI().getScheme(); + } + + @Override + @Nullable + protected String userAgent(HttpUriRequest request) { + Header header = request.getFirstHeader("User-Agent"); + return header != null ? header.getValue() : null; + } + + @Override + @Nullable + protected Long requestContentLength(HttpUriRequest request, HttpResponse unused) { + return null; + } + + @Override + @Nullable + protected Long requestContentLengthUncompressed(HttpUriRequest request, HttpResponse unused) { + return null; + } + + @Override + protected Integer statusCode(HttpUriRequest request, HttpResponse response) { + if (response == null) { + return null; + } + return response.getStatusLine().getStatusCode(); + } + + @Override + @Nullable + protected String flavor(HttpUriRequest request, HttpResponse response) { + ProtocolVersion protocolVersion = request.getRequestLine().getProtocolVersion(); + String protocol = protocolVersion.getProtocol(); + if (!protocol.equals("HTTP")) { + return null; + } + int major = protocolVersion.getMajor(); + int minor = protocolVersion.getMinor(); + if (major == 1 && minor == 0) { + return SemanticAttributes.HttpFlavorValues.HTTP_1_0; + } + if (major == 1 && minor == 1) { + return SemanticAttributes.HttpFlavorValues.HTTP_1_1; + } + if (major == 2 && minor == 0) { + return SemanticAttributes.HttpFlavorValues.HTTP_2_0; + } + logger.debug("unexpected http protocol version: " + protocolVersion); + return null; + } + + @Override + @Nullable + protected Long responseContentLength(HttpUriRequest request, HttpResponse response) { + return null; + } + + @Override + @Nullable + protected Long responseContentLengthUncompressed(HttpUriRequest request, HttpResponse response) { + return null; + } + + @Override + @Nullable + protected String serverName(HttpUriRequest request, HttpResponse response) { + return null; + } + + @Override + @Nullable + protected String route(HttpUriRequest request) { + return null; + } + + @Override + @Nullable + protected String clientIp(HttpUriRequest request, HttpResponse response) { + return null; + } +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientInstrumentationModule.java b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientInstrumentationModule.java index 69238f9bd7..5f8cd76254 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientInstrumentationModule.java +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientInstrumentationModule.java @@ -7,7 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; -import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0.ApacheHttpClientTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0.ApacheHttpClientInstrumenters.instrumenter; import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext; import static java.util.Collections.singletonList; import static net.bytebuddy.matcher.ElementMatchers.isAbstract; @@ -147,16 +147,17 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { Context parentContext = currentContext(); - if (!tracer().shouldStartSpan(parentContext)) { + if (!instrumenter().shouldStart(parentContext, request)) { return; } - context = tracer().startSpan(parentContext, request); + context = instrumenter().start(parentContext, request); scope = context.makeCurrent(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( + @Advice.Argument(0) HttpUriRequest request, @Advice.Return Object result, @Advice.Thrown Throwable throwable, @Advice.Local("otelContext") Context context, @@ -166,7 +167,7 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule } scope.close(); - ApacheHttpClientHelper.doMethodExit(context, result, throwable); + ApacheHttpClientHelper.doMethodExit(context, request, result, throwable); } } @@ -179,21 +180,23 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { Context parentContext = currentContext(); - if (!tracer().shouldStartSpan(parentContext)) { + if (!instrumenter().shouldStart(parentContext, request)) { return; } - context = tracer().startSpan(parentContext, request); + context = instrumenter().start(parentContext, request); scope = context.makeCurrent(); // Wrap the handler so we capture the status code if (handler != null) { - handler = new WrappingStatusSettingResponseHandler<>(context, parentContext, handler); + handler = + new WrappingStatusSettingResponseHandler<>(context, parentContext, handler, request); } } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void methodExit( + @Advice.Argument(0) HttpUriRequest request, @Advice.Return Object result, @Advice.Thrown Throwable throwable, @Advice.Local("otelContext") Context context, @@ -203,7 +206,7 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule } scope.close(); - ApacheHttpClientHelper.doMethodExit(context, result, throwable); + ApacheHttpClientHelper.doMethodExit(context, request, result, throwable); } } @@ -212,14 +215,18 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule public static void methodEnter( @Advice.Argument(0) HttpHost host, @Advice.Argument(1) HttpRequest request, + @Advice.Local("otelHttpUriRequest") HttpUriRequest httpUriRequest, @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { Context parentContext = currentContext(); - if (!tracer().shouldStartSpan(parentContext)) { + + httpUriRequest = new HostAndRequestAsHttpUriRequest(host, request); + + if (!instrumenter().shouldStart(parentContext, httpUriRequest)) { return; } - context = tracer().startSpan(parentContext, host, request); + context = instrumenter().start(parentContext, httpUriRequest); scope = context.makeCurrent(); } @@ -227,6 +234,7 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule public static void methodExit( @Advice.Return Object result, @Advice.Thrown Throwable throwable, + @Advice.Local("otelHttpUriRequest") HttpUriRequest httpUriRequest, @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { if (scope == null) { @@ -234,7 +242,7 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule } scope.close(); - ApacheHttpClientHelper.doMethodExit(context, result, throwable); + ApacheHttpClientHelper.doMethodExit(context, httpUriRequest, result, throwable); } } @@ -245,19 +253,22 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule @Advice.Argument(0) HttpHost host, @Advice.Argument(1) HttpRequest request, @Advice.Argument(value = 2, readOnly = false) ResponseHandler handler, + @Advice.Local("otelHttpUriRequest") HttpUriRequest httpUriRequest, @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { Context parentContext = currentContext(); - if (!tracer().shouldStartSpan(parentContext)) { + if (!instrumenter().shouldStart(parentContext, httpUriRequest)) { return; } - context = tracer().startSpan(parentContext, host, request); + context = instrumenter().start(parentContext, httpUriRequest); scope = context.makeCurrent(); // Wrap the handler so we capture the status code if (handler != null) { - handler = new WrappingStatusSettingResponseHandler<>(context, parentContext, handler); + handler = + new WrappingStatusSettingResponseHandler<>( + context, parentContext, handler, httpUriRequest); } } @@ -265,6 +276,7 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule public static void methodExit( @Advice.Return Object result, @Advice.Thrown Throwable throwable, + @Advice.Local("otelHttpUriRequest") HttpUriRequest httpUriRequest, @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { if (scope == null) { @@ -272,7 +284,7 @@ public class ApacheHttpClientInstrumentationModule extends InstrumentationModule } scope.close(); - ApacheHttpClientHelper.doMethodExit(context, result, throwable); + ApacheHttpClientHelper.doMethodExit(context, httpUriRequest, result, throwable); } } } diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientInstrumenters.java b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientInstrumenters.java new file mode 100644 index 0000000000..ced274617a --- /dev/null +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientInstrumenters.java @@ -0,0 +1,46 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpAttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpUriRequest; + +public final class ApacheHttpClientInstrumenters { + private static final String INSTRUMENTATION_NAME = + "io.opentelemetry.javaagent.apache-httpclient-4.0"; + + private static final Instrumenter INSTRUMENTER; + + static { + HttpAttributesExtractor httpAttributesExtractor = + new ApacheHttpClientHttpAttributesExtractor(); + SpanNameExtractor spanNameExtractor = + HttpSpanNameExtractor.create(httpAttributesExtractor); + SpanStatusExtractor spanStatusExtractor = + HttpSpanStatusExtractor.create(httpAttributesExtractor); + + INSTRUMENTER = + Instrumenter.newBuilder( + GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, spanNameExtractor) + .setSpanStatusExtractor(spanStatusExtractor) + .addAttributesExtractor(httpAttributesExtractor) + .addAttributesExtractor(new ApacheHttpClientNetAttributesExtractor()) + .newClientInstrumenter(HttpHeaderSetter.INSTANCE); + } + + public static Instrumenter instrumenter() { + return INSTRUMENTER; + } + + private ApacheHttpClientInstrumenters() {} +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientNetAttributesExtractor.java b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientNetAttributesExtractor.java new file mode 100644 index 0000000000..90f582f8a1 --- /dev/null +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientNetAttributesExtractor.java @@ -0,0 +1,49 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0; + +import io.opentelemetry.instrumentation.api.instrumenter.net.NetAttributesExtractor; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import java.net.URI; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpUriRequest; +import org.checkerframework.checker.nullness.qual.Nullable; + +final class ApacheHttpClientNetAttributesExtractor + extends NetAttributesExtractor { + + @Override + protected String transport(HttpUriRequest request) { + return SemanticAttributes.NetTransportValues.IP_TCP; + } + + @Override + protected @Nullable String peerName(HttpUriRequest request, @Nullable HttpResponse response) { + return request.getURI().getHost(); + } + + @Override + protected Integer peerPort(HttpUriRequest request, @Nullable HttpResponse response) { + URI uri = request.getURI(); + int port = uri.getPort(); + if (port != -1) { + return port; + } + switch (uri.getScheme()) { + case "http": + return 80; + case "https": + return 443; + default: + return null; + } + } + + @Override + protected @Nullable String peerIp(HttpUriRequest request, @Nullable HttpResponse response) { + return null; + } +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientTracer.java b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientTracer.java deleted file mode 100644 index ddec4dfe35..0000000000 --- a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientTracer.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0; - -import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0.HttpHeadersInjectAdapter.SETTER; - -import io.opentelemetry.context.Context; -import io.opentelemetry.context.propagation.TextMapSetter; -import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer; -import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes; -import java.net.URI; -import org.apache.http.Header; -import org.apache.http.HttpHost; -import org.apache.http.HttpMessage; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpUriRequest; -import org.checkerframework.checker.nullness.qual.Nullable; - -public class ApacheHttpClientTracer - extends HttpClientTracer { - - private static final ApacheHttpClientTracer TRACER = new ApacheHttpClientTracer(); - - private ApacheHttpClientTracer() { - super(NetPeerAttributes.INSTANCE); - } - - public static ApacheHttpClientTracer tracer() { - return TRACER; - } - - public Context startSpan(Context parentContext, HttpHost host, HttpRequest request) { - HttpUriRequest httpUriRequest; - if (request instanceof HttpUriRequest) { - httpUriRequest = (HttpUriRequest) request; - } else { - httpUriRequest = new HostAndRequestAsHttpUriRequest(host, request); - } - return startSpan(parentContext, httpUriRequest); - } - - public Context startSpan(Context parentContext, HttpUriRequest request) { - return startSpan(parentContext, request, request); - } - - @Override - protected String method(HttpUriRequest httpRequest) { - return httpRequest.getMethod(); - } - - @Override - @Nullable - protected String flavor(HttpUriRequest httpUriRequest) { - return httpUriRequest.getProtocolVersion().toString(); - } - - @Override - protected URI url(HttpUriRequest request) { - return request.getURI(); - } - - @Override - protected Integer status(HttpResponse httpResponse) { - return httpResponse.getStatusLine().getStatusCode(); - } - - @Override - protected String requestHeader(HttpUriRequest request, String name) { - return header(request, name); - } - - @Override - protected String responseHeader(HttpResponse response, String name) { - return header(response, name); - } - - @Override - protected TextMapSetter getSetter() { - return SETTER; - } - - private static String header(HttpMessage message, String name) { - Header header = message.getFirstHeader(name); - return header != null ? header.getValue() : null; - } - - @Override - protected String getInstrumentationName() { - return "io.opentelemetry.javaagent.apache-httpclient-4.0"; - } -} diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/HostAndRequestAsHttpUriRequest.java b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/HostAndRequestAsHttpUriRequest.java index a17c2edb6d..76ff3ad345 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/HostAndRequestAsHttpUriRequest.java +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/HostAndRequestAsHttpUriRequest.java @@ -15,7 +15,8 @@ import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.message.AbstractHttpMessage; /** Wraps HttpHost and HttpRequest into a HttpUriRequest for tracers and injectors. */ -public class HostAndRequestAsHttpUriRequest extends AbstractHttpMessage implements HttpUriRequest { +public final class HostAndRequestAsHttpUriRequest extends AbstractHttpMessage + implements HttpUriRequest { private final String method; private final RequestLine requestLine; @@ -74,8 +75,4 @@ public class HostAndRequestAsHttpUriRequest extends AbstractHttpMessage implemen public java.net.URI getURI() { return uri; } - - public HttpRequest getActualRequest() { - return actualRequest; - } } diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/HttpHeadersInjectAdapter.java b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/HttpHeaderSetter.java similarity index 71% rename from instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/HttpHeadersInjectAdapter.java rename to instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/HttpHeaderSetter.java index 049f0911ca..ae7882dd45 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/HttpHeadersInjectAdapter.java +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/HttpHeaderSetter.java @@ -8,9 +8,8 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0; import io.opentelemetry.context.propagation.TextMapSetter; import org.apache.http.client.methods.HttpUriRequest; -class HttpHeadersInjectAdapter implements TextMapSetter { - - public static final HttpHeadersInjectAdapter SETTER = new HttpHeadersInjectAdapter(); +enum HttpHeaderSetter implements TextMapSetter { + INSTANCE; @Override public void set(HttpUriRequest carrier, String key, String value) { diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/WrappingStatusSettingResponseHandler.java b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/WrappingStatusSettingResponseHandler.java index bf05b7d4ae..19d8b28e6a 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/WrappingStatusSettingResponseHandler.java +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/WrappingStatusSettingResponseHandler.java @@ -5,29 +5,35 @@ package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0; -import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0.ApacheHttpClientTracer.tracer; +import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v4_0.ApacheHttpClientInstrumenters.instrumenter; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import java.io.IOException; import org.apache.http.HttpResponse; import org.apache.http.client.ResponseHandler; +import org.apache.http.client.methods.HttpUriRequest; -public class WrappingStatusSettingResponseHandler implements ResponseHandler { - final Context context; - final Context parentContext; - final ResponseHandler handler; +public final class WrappingStatusSettingResponseHandler implements ResponseHandler { + private final Context context; + private final Context parentContext; + private final ResponseHandler handler; + private final HttpUriRequest httpUriRequest; public WrappingStatusSettingResponseHandler( - Context context, Context parentContext, ResponseHandler handler) { + Context context, + Context parentContext, + ResponseHandler handler, + HttpUriRequest httpUriRequest) { this.context = context; this.parentContext = parentContext; this.handler = handler; + this.httpUriRequest = httpUriRequest; } @Override public T handleResponse(HttpResponse response) throws IOException { - tracer().end(context, response); + instrumenter().end(context, httpUriRequest, response, null); // ending the span before executing the callback handler (and scoping the callback handler to // the parent context), even though we are inside of a synchronous http client callback // underneath HttpClient.execute(..), in order to not attribute other CLIENT span timings that diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/test/groovy/ApacheHttpClientTest.groovy b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/test/groovy/ApacheHttpClientTest.groovy index 7674852d96..fc0812992b 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/test/groovy/ApacheHttpClientTest.groovy +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/test/groovy/ApacheHttpClientTest.groovy @@ -3,8 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.instrumentation.test.AgentTestTrait import io.opentelemetry.instrumentation.test.base.HttpClientTest +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes import java.util.function.Consumer import org.apache.http.HttpHost import org.apache.http.HttpRequest @@ -40,6 +42,15 @@ abstract class ApacheHttpClientTest extends HttpClientTes return request } + @Override + List> extraAttributes() { + [ + SemanticAttributes.HTTP_SCHEME, + SemanticAttributes.HTTP_SCHEME, + SemanticAttributes.HTTP_TARGET, + ] + } + // compilation fails with @Override annotation on this method (groovy quirk?) int sendRequest(T request, String method, URI uri, Map headers) { def response = executeRequest(request, uri)