Convert google-http-client-1.19 to instrumenter api (#3932)

* Convert google-http-client-1.19 to instrumenter api

* remove some nullable annotations

* remove nullable
This commit is contained in:
Lauri Tulmin 2021-08-25 23:57:36 +03:00 committed by GitHub
parent 6f22d90aa6
commit c0aad71650
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 211 additions and 105 deletions

View File

@ -0,0 +1,91 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.googlehttpclient;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpAttributesExtractor;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import org.checkerframework.checker.nullness.qual.Nullable;
final class GoogleHttpClientHttpAttributesExtractor
extends HttpAttributesExtractor<HttpRequest, HttpResponse> {
@Override
protected @Nullable String method(HttpRequest httpRequest) {
return httpRequest.getRequestMethod();
}
@Override
protected String url(HttpRequest httpRequest) {
return httpRequest.getUrl().build();
}
@Override
protected String target(HttpRequest httpRequest) {
return httpRequest.getUrl().buildRelativeUrl();
}
@Override
protected String host(HttpRequest httpRequest) {
return httpRequest.getUrl().getHost();
}
@Override
protected String scheme(HttpRequest httpRequest) {
return httpRequest.getUrl().getScheme();
}
@Override
protected @Nullable String userAgent(HttpRequest httpRequest) {
return httpRequest.getHeaders().getUserAgent();
}
@Override
protected @Nullable Long requestContentLength(
HttpRequest httpRequest, @Nullable HttpResponse httpResponse) {
return null;
}
@Override
protected @Nullable Long requestContentLengthUncompressed(
HttpRequest httpRequest, @Nullable HttpResponse httpResponse) {
return null;
}
@Override
protected String flavor(HttpRequest httpRequest, @Nullable HttpResponse httpResponse) {
return SemanticAttributes.HttpFlavorValues.HTTP_1_1;
}
@Override
protected @Nullable Integer statusCode(HttpRequest httpRequest, HttpResponse httpResponse) {
return httpResponse.getStatusCode();
}
@Override
protected @Nullable Long responseContentLength(
HttpRequest httpRequest, HttpResponse httpResponse) {
return null;
}
@Override
protected @Nullable Long responseContentLengthUncompressed(
HttpRequest httpRequest, HttpResponse httpResponse) {
return null;
}
@Override
protected @Nullable String route(HttpRequest httpRequest) {
return null;
}
@Override
protected @Nullable String serverName(
HttpRequest httpRequest, @Nullable HttpResponse httpResponse) {
return null;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.googlehttpclient;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import io.opentelemetry.instrumentation.api.instrumenter.net.NetAttributesExtractor;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import org.checkerframework.checker.nullness.qual.Nullable;
final class GoogleHttpClientNetAttributesExtractor
extends NetAttributesExtractor<HttpRequest, HttpResponse> {
@Override
public String transport(HttpRequest request) {
return SemanticAttributes.NetTransportValues.IP_TCP;
}
@Override
public @Nullable String peerName(HttpRequest request, @Nullable HttpResponse response) {
return request.getUrl().getHost();
}
@Override
public Integer peerPort(HttpRequest request, @Nullable HttpResponse response) {
int port = request.getUrl().getPort();
if (port != -1) {
return port;
}
return null;
}
@Override
public @Nullable String peerIp(HttpRequest request, @Nullable HttpResponse response) {
return null;
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.googlehttpclient;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
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.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
import io.opentelemetry.javaagent.instrumentation.api.instrumenter.PeerServiceAttributesExtractor;
public class GoogleHttpClientSingletons {
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.google-http-client-1.19";
private static final Instrumenter<HttpRequest, HttpResponse> INSTRUMENTER;
static {
HttpAttributesExtractor<HttpRequest, HttpResponse> httpAttributesExtractor =
new GoogleHttpClientHttpAttributesExtractor();
SpanNameExtractor<? super HttpRequest> spanNameExtractor =
HttpSpanNameExtractor.create(httpAttributesExtractor);
SpanStatusExtractor<? super HttpRequest, ? super HttpResponse> spanStatusExtractor =
HttpSpanStatusExtractor.create(httpAttributesExtractor);
GoogleHttpClientNetAttributesExtractor netAttributesExtractor =
new GoogleHttpClientNetAttributesExtractor();
INSTRUMENTER =
Instrumenter.<HttpRequest, HttpResponse>newBuilder(
GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, spanNameExtractor)
.setSpanStatusExtractor(spanStatusExtractor)
.addAttributesExtractor(httpAttributesExtractor)
.addAttributesExtractor(netAttributesExtractor)
.addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesExtractor))
.addRequestMetrics(HttpClientMetrics.get())
.newClientInstrumenter(new HttpHeaderSetter());
}
public static Instrumenter<HttpRequest, HttpResponse> instrumenter() {
return INSTRUMENTER;
}
private GoogleHttpClientSingletons() {}
}

View File

@ -1,78 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.googlehttpclient;
import static io.opentelemetry.javaagent.instrumentation.googlehttpclient.HeadersInjectAdapter.SETTER;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
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 java.net.URISyntaxException;
public class GoogleHttpClientTracer
extends HttpClientTracer<HttpRequest, HttpHeaders, HttpResponse> {
private static final GoogleHttpClientTracer TRACER = new GoogleHttpClientTracer();
private GoogleHttpClientTracer() {
super(NetPeerAttributes.INSTANCE);
}
public static GoogleHttpClientTracer tracer() {
return TRACER;
}
public Context startSpan(Context parentContext, HttpRequest request) {
return startSpan(parentContext, request, request.getHeaders());
}
@Override
protected String getInstrumentationName() {
return "io.opentelemetry.google-http-client-1.19";
}
@Override
protected String method(HttpRequest httpRequest) {
return httpRequest.getRequestMethod();
}
@Override
protected URI url(HttpRequest httpRequest) throws URISyntaxException {
// Google uses %20 (space) instead of "+" for spaces in the fragment
// Add "+" back for consistency with the other http client instrumentations
String url = httpRequest.getUrl().build();
String fixedUrl = url.replaceAll("%20", "+");
return new URI(fixedUrl);
}
@Override
protected Integer status(HttpResponse httpResponse) {
return httpResponse.getStatusCode();
}
@Override
protected String requestHeader(HttpRequest httpRequest, String name) {
return header(httpRequest.getHeaders(), name);
}
@Override
protected String responseHeader(HttpResponse httpResponse, String name) {
return header(httpResponse.getHeaders(), name);
}
@Override
protected TextMapSetter<HttpHeaders> getSetter() {
return SETTER;
}
private static String header(HttpHeaders headers, String name) {
return headers.getFirstHeaderStringValue(name);
}
}

View File

@ -6,7 +6,7 @@
package io.opentelemetry.javaagent.instrumentation.googlehttpclient;
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
import static io.opentelemetry.javaagent.instrumentation.googlehttpclient.GoogleHttpClientTracer.tracer;
import static io.opentelemetry.javaagent.instrumentation.googlehttpclient.GoogleHttpClientSingletons.instrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
import static net.bytebuddy.matcher.ElementMatchers.named;
@ -67,15 +67,16 @@ public class GoogleHttpRequestInstrumentation implements TypeInstrumentation {
return;
}
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.This HttpRequest request,
@Advice.Return HttpResponse response,
@Advice.Thrown Throwable throwable,
@Advice.Local("otelContext") Context context,
@ -85,7 +86,7 @@ public class GoogleHttpRequestInstrumentation implements TypeInstrumentation {
}
scope.close();
tracer().endMaybeExceptionally(context, response, throwable);
instrumenter().end(context, request, response, throwable);
}
}
@ -98,11 +99,10 @@ public class GoogleHttpRequestInstrumentation implements TypeInstrumentation {
@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();
InstrumentationContext.get(HttpRequest.class, Context.class).put(request, context);
@ -110,6 +110,7 @@ public class GoogleHttpRequestInstrumentation implements TypeInstrumentation {
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void methodExit(
@Advice.This HttpRequest request,
@Advice.Thrown Throwable throwable,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {
@ -119,7 +120,7 @@ public class GoogleHttpRequestInstrumentation implements TypeInstrumentation {
scope.close();
if (throwable != null) {
tracer().endExceptionally(context, throwable);
instrumenter().end(context, request, null, throwable);
}
}
}

View File

@ -1,19 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.googlehttpclient;
import com.google.api.client.http.HttpHeaders;
import io.opentelemetry.context.propagation.TextMapSetter;
public class HeadersInjectAdapter implements TextMapSetter<HttpHeaders> {
public static final HeadersInjectAdapter SETTER = new HeadersInjectAdapter();
@Override
public void set(HttpHeaders carrier, String key, String value) {
carrier.put(key, value);
}
}

View File

@ -0,0 +1,17 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.googlehttpclient;
import com.google.api.client.http.HttpRequest;
import io.opentelemetry.context.propagation.TextMapSetter;
public class HttpHeaderSetter implements TextMapSetter<HttpRequest> {
@Override
public void set(HttpRequest carrier, String key, String value) {
carrier.getHeaders().set(key, value);
}
}

View File

@ -83,6 +83,9 @@ abstract class AbstractGoogleHttpClientTest extends HttpClientTest<HttpRequest>
"${SemanticAttributes.HTTP_METHOD.key}" method
"${SemanticAttributes.HTTP_STATUS_CODE.key}" 500
"${SemanticAttributes.HTTP_FLAVOR.key}" "1.1"
"${SemanticAttributes.HTTP_HOST.key}" "localhost"
"${SemanticAttributes.HTTP_SCHEME.key}" "http"
"${SemanticAttributes.HTTP_TARGET.key}" "/error"
}
}
serverSpan(it, 1, span(0))