Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update apache-httpclient-5.0 to Instrumenter API #3062

Merged
merged 11 commits into from
May 24, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public static void methodEnter(
// Wrap the handler so we capture the status code
if (handler != null) {
handler =
new WrappingStatusSettingResponseHandler<>(context, parentContext, handler, request);
new WrappingStatusSettingResponseHandler<>(context, parentContext, request, handler);
}
}

Expand All @@ -215,34 +215,34 @@ public static class RequestAdvice {
public static void methodEnter(
@Advice.Argument(0) HttpHost host,
@Advice.Argument(1) HttpRequest request,
@Advice.Local("otelHttpUriRequest") HttpUriRequest httpUriRequest,
@Advice.Local("fullRequest") HttpUriRequest fullRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
Context parentContext = currentContext();

httpUriRequest = new HostAndRequestAsHttpUriRequest(host, request);
fullRequest = new HostAndRequestAsHttpUriRequest(host, request);

if (!instrumenter().shouldStart(parentContext, httpUriRequest)) {
if (!instrumenter().shouldStart(parentContext, fullRequest)) {
return;
}

context = instrumenter().start(parentContext, httpUriRequest);
context = instrumenter().start(parentContext, fullRequest);
scope = context.makeCurrent();
}

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void methodExit(
@Advice.Return Object result,
@Advice.Thrown Throwable throwable,
@Advice.Local("otelHttpUriRequest") HttpUriRequest httpUriRequest,
@Advice.Local("fullRequest") HttpUriRequest fullRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}

scope.close();
ApacheHttpClientHelper.doMethodExit(context, httpUriRequest, result, throwable);
ApacheHttpClientHelper.doMethodExit(context, fullRequest, result, throwable);
}
}

Expand All @@ -253,38 +253,38 @@ public static void methodEnter(
@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("fullRequest") HttpUriRequest fullRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
Context parentContext = currentContext();
if (!instrumenter().shouldStart(parentContext, httpUriRequest)) {
if (!instrumenter().shouldStart(parentContext, fullRequest)) {
return;
}

context = instrumenter().start(parentContext, httpUriRequest);
context = instrumenter().start(parentContext, fullRequest);
scope = context.makeCurrent();

// Wrap the handler so we capture the status code
if (handler != null) {
handler =
new WrappingStatusSettingResponseHandler<>(
context, parentContext, handler, httpUriRequest);
context, parentContext, fullRequest, handler);
}
}

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void methodExit(
@Advice.Return Object result,
@Advice.Thrown Throwable throwable,
@Advice.Local("otelHttpUriRequest") HttpUriRequest httpUriRequest,
@Advice.Local("fullRequest") HttpUriRequest fullRequest,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
if (scope == null) {
return;
}

scope.close();
ApacheHttpClientHelper.doMethodExit(context, httpUriRequest, result, throwable);
ApacheHttpClientHelper.doMethodExit(context, fullRequest, result, throwable);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

final class ApacheHttpClientNetAttributesExtractor
extends NetAttributesExtractor<HttpUriRequest, HttpResponse> {

private static final Logger logger =
LoggerFactory.getLogger(ApacheHttpClientNetAttributesExtractor.class);

@Override
protected String transport(HttpUriRequest request) {
return SemanticAttributes.NetTransportValues.IP_TCP;
Expand All @@ -38,6 +43,7 @@ protected Integer peerPort(HttpUriRequest request, @Nullable HttpResponse respon
case "https":
return 443;
default:
logger.debug("no default port mapping for scheme: {}", uri.getScheme());
return null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,20 @@
public final class WrappingStatusSettingResponseHandler<T> implements ResponseHandler<T> {
private final Context context;
private final Context parentContext;
private final HttpUriRequest request;
private final ResponseHandler<T> handler;
private final HttpUriRequest httpUriRequest;

public WrappingStatusSettingResponseHandler(
Context context,
Context parentContext,
ResponseHandler<T> handler,
HttpUriRequest httpUriRequest) {
Context context, Context parentContext, HttpUriRequest request, ResponseHandler<T> handler) {
this.context = context;
this.parentContext = parentContext;
this.request = request;
this.handler = handler;
this.httpUriRequest = httpUriRequest;
}

@Override
public T handleResponse(HttpResponse response) throws IOException {
instrumenter().end(context, httpUriRequest, response, null);
instrumenter().end(context, request, 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ abstract class ApacheHttpClientTest<T extends HttpRequest> extends HttpClientTes
@Override
List<AttributeKey<?>> extraAttributes() {
[
SemanticAttributes.HTTP_SCHEME,
SemanticAttributes.HTTP_SCHEME,
SemanticAttributes.HTTP_TARGET,
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@

package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v5_0;

import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v5_0.ApacheHttpClientTracer.tracer;
import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v5_0.ApacheHttpClientInstrumenters.instrumenter;

import io.opentelemetry.context.Context;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.HttpResponse;

public class ApacheHttpClientHelper {

public static void doMethodExit(Context context, Object result, Throwable throwable) {
public static void doMethodExit(
Context context, ClassicHttpRequest 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
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.apachehttpclient.v5_0;

import io.opentelemetry.instrumentation.api.instrumenter.http.HttpAttributesExtractor;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.ProtocolVersion;
import org.apache.hc.core5.net.URIAuthority;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

final class ApacheHttpClientHttpAttributesExtractor
extends HttpAttributesExtractor<ClassicHttpRequest, HttpResponse> {

private static final Logger logger =
LoggerFactory.getLogger(ApacheHttpClientHttpAttributesExtractor.class);

@Override
protected String method(ClassicHttpRequest request) {
return request.getMethod();
}

@Override
protected String url(ClassicHttpRequest request) {
// similar to org.apache.hc.core5.http.message.BasicHttpRequest.getUri()
// not calling getUri() to avoid unnecessary conversion
StringBuilder url = new StringBuilder();
URIAuthority authority = request.getAuthority();
if (authority != null) {
String scheme = request.getScheme();
if (scheme != null) {
url.append(scheme);
url.append("://");
} else {
url.append("http://");
}
url.append(authority.getHostName());
int port = authority.getPort();
if (port >= 0) {
url.append(":");
url.append(port);
}
}
String path = request.getPath();
if (path != null) {
if (url.length() > 0 && !path.startsWith("/")) {
url.append("/");
}
url.append(path);
} else {
url.append("/");
}
return url.toString();
}

@Override
protected String target(ClassicHttpRequest request) {
return request.getRequestUri();
}

@Override
@Nullable
protected String host(ClassicHttpRequest request) {
Header header = request.getFirstHeader("Host");
if (header != null) {
return header.getValue();
}
return null;
}

@Override
protected String scheme(ClassicHttpRequest request) {
String scheme = request.getScheme();
return scheme != null ? scheme : "http";
}

@Override
@Nullable
protected String userAgent(ClassicHttpRequest request) {
Header header = request.getFirstHeader("User-Agent");
return header != null ? header.getValue() : null;
}

@Override
@Nullable
protected Long requestContentLength(ClassicHttpRequest request, @Nullable HttpResponse response) {
return null;
}

@Override
@Nullable
protected Long requestContentLengthUncompressed(
ClassicHttpRequest request, @Nullable HttpResponse response) {
return null;
}

@Override
protected Integer statusCode(ClassicHttpRequest request, HttpResponse response) {
return response.getCode();
}

@Override
@Nullable
protected String flavor(ClassicHttpRequest request, @Nullable HttpResponse response) {
ProtocolVersion protocolVersion = request.getVersion();
if (protocolVersion == null) {
return SemanticAttributes.HttpFlavorValues.HTTP_1_1;
}
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(ClassicHttpRequest request, HttpResponse response) {
return null;
}

@Override
@Nullable
protected Long responseContentLengthUncompressed(
ClassicHttpRequest request, HttpResponse response) {
return null;
}

@Override
@Nullable
protected String serverName(ClassicHttpRequest request, @Nullable HttpResponse response) {
return null;
}

@Override
@Nullable
protected String route(ClassicHttpRequest request) {
return null;
}

@Override
@Nullable
protected String clientIp(ClassicHttpRequest request, @Nullable HttpResponse response) {
return null;
}
}
Loading