diff --git a/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpClientHttpAttributesExtractor.java b/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpClientHttpAttributesExtractor.java new file mode 100644 index 0000000000..6ea5fdfff7 --- /dev/null +++ b/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpClientHttpAttributesExtractor.java @@ -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 { + + @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; + } +} diff --git a/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpClientNetAttributesExtractor.java b/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpClientNetAttributesExtractor.java new file mode 100644 index 0000000000..a69f7f9643 --- /dev/null +++ b/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpClientNetAttributesExtractor.java @@ -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 { + + @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; + } +} diff --git a/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpClientSingletons.java b/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpClientSingletons.java new file mode 100644 index 0000000000..8d0caa07cd --- /dev/null +++ b/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpClientSingletons.java @@ -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 INSTRUMENTER; + + static { + HttpAttributesExtractor httpAttributesExtractor = + new GoogleHttpClientHttpAttributesExtractor(); + SpanNameExtractor spanNameExtractor = + HttpSpanNameExtractor.create(httpAttributesExtractor); + SpanStatusExtractor spanStatusExtractor = + HttpSpanStatusExtractor.create(httpAttributesExtractor); + GoogleHttpClientNetAttributesExtractor netAttributesExtractor = + new GoogleHttpClientNetAttributesExtractor(); + + INSTRUMENTER = + Instrumenter.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 instrumenter() { + return INSTRUMENTER; + } + + private GoogleHttpClientSingletons() {} +} diff --git a/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpClientTracer.java b/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpClientTracer.java deleted file mode 100644 index 9dbe7fda72..0000000000 --- a/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpClientTracer.java +++ /dev/null @@ -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 { - 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 getSetter() { - return SETTER; - } - - private static String header(HttpHeaders headers, String name) { - return headers.getFirstHeaderStringValue(name); - } -} diff --git a/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpRequestInstrumentation.java b/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpRequestInstrumentation.java index 18e23a74a1..09d28fb7ca 100644 --- a/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpRequestInstrumentation.java +++ b/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/GoogleHttpRequestInstrumentation.java @@ -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); } } } diff --git a/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/HeadersInjectAdapter.java b/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/HeadersInjectAdapter.java deleted file mode 100644 index 370b70f1fe..0000000000 --- a/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/HeadersInjectAdapter.java +++ /dev/null @@ -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 { - - public static final HeadersInjectAdapter SETTER = new HeadersInjectAdapter(); - - @Override - public void set(HttpHeaders carrier, String key, String value) { - carrier.put(key, value); - } -} diff --git a/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/HttpHeaderSetter.java b/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/HttpHeaderSetter.java new file mode 100644 index 0000000000..aabd166b1c --- /dev/null +++ b/instrumentation/google-http-client-1.19/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/HttpHeaderSetter.java @@ -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 { + + @Override + public void set(HttpRequest carrier, String key, String value) { + carrier.getHeaders().set(key, value); + } +} diff --git a/instrumentation/google-http-client-1.19/javaagent/src/test/groovy/AbstractGoogleHttpClientTest.groovy b/instrumentation/google-http-client-1.19/javaagent/src/test/groovy/AbstractGoogleHttpClientTest.groovy index 617a9988c6..53b3fbd227 100644 --- a/instrumentation/google-http-client-1.19/javaagent/src/test/groovy/AbstractGoogleHttpClientTest.groovy +++ b/instrumentation/google-http-client-1.19/javaagent/src/test/groovy/AbstractGoogleHttpClientTest.groovy @@ -83,6 +83,9 @@ abstract class AbstractGoogleHttpClientTest extends HttpClientTest "${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))