diff --git a/docs/supported-libraries.md b/docs/supported-libraries.md index 0667d90dc908..5b0b780feb90 100644 --- a/docs/supported-libraries.md +++ b/docs/supported-libraries.md @@ -55,7 +55,7 @@ These are the supported libraries and frameworks: | [Dropwizard Views](https://www.dropwizard.io/en/latest/manual/views.html) | 0.7+ | N/A | Controller Spans [3] | | [Eclipse Grizzly](https://javaee.github.io/grizzly/httpserverframework.html) | 2.3+ | N/A | [HTTP Server Spans], [HTTP Server Metrics] | | [Eclipse Jersey](https://eclipse-ee4j.github.io/jersey/) | 2.0+ | N/A | Provides `http.route` [2], Controller Spans [3] | -| [Eclipse Jetty HTTP Client](https://www.eclipse.org/jetty/javadoc/jetty-9/org/eclipse/jetty/client/HttpClient.html) | 9.2+ (not including 10+ yet) | [opentelemetry-jetty-httpclient-9.2](../instrumentation/jetty-httpclient/jetty-httpclient-9.2/library) | [HTTP Client Spans], [HTTP Client Metrics] | +| [Eclipse Jetty HTTP Client](https://www.eclipse.org/jetty/javadoc/jetty-9/org/eclipse/jetty/client/HttpClient.html) | 9.2 - 9.4.x,
12.0+ | [opentelemetry-jetty-httpclient-9.2](../instrumentation/jetty-httpclient/jetty-httpclient-9.2/library)
[opentelemetry-jetty-httpclient-12.0](../instrumentation/jetty-httpclient/jetty-httpclient-12.0/library) | [HTTP Client Spans], [HTTP Client Metrics] | | [Eclipse Metro](https://projects.eclipse.org/projects/ee4j.metro) | 2.2+ | N/A | Provides `http.route` [2], Controller Spans [3] | | [Eclipse Mojarra](https://projects.eclipse.org/projects/ee4j.mojarra) | 1.2+ | N/A | Provides `http.route` [2], Controller Spans [3] | | [Elasticsearch API Client](https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/index.html) | 7.16 - 7.17.19,
8.0 - 8.9.+ [4] | N/A | [Elasticsearch Client Spans] | diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/build.gradle.kts b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/build.gradle.kts new file mode 100644 index 000000000000..ae4b56855e0c --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +muzzle { + pass { + group.set("org.eclipse.jetty") + module.set("jetty-client") + versions.set("[12,)") + } +} + +otelJava { + minJavaVersionSupported.set(JavaVersion.VERSION_17) +} + +dependencies { + implementation(project(":instrumentation:jetty-httpclient:jetty-httpclient-12.0:library")) + + library("org.eclipse.jetty:jetty-client:12.0.0") + + testInstrumentation(project(":instrumentation:jetty-httpclient:jetty-httpclient-9.2:javaagent")) + + testImplementation(project(":instrumentation:jetty-httpclient:jetty-httpclient-12.0:testing")) +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyClient12ResponseListenersInstrumentation.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyClient12ResponseListenersInstrumentation.java new file mode 100644 index 000000000000..940ede1b69d1 --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyClient12ResponseListenersInstrumentation.java @@ -0,0 +1,108 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v12_0; + +import static io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v12_0.JettyHttpClientSingletons.JETTY_CLIENT_CONTEXT_KEY; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.nameContains; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.eclipse.jetty.client.Response; +import org.eclipse.jetty.client.Result; + +public class JettyClient12ResponseListenersInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("org.eclipse.jetty.client.transport.ResponseListeners"); + } + + @Override + public void transform(TypeTransformer transformer) { + // for response listeners + transformer.applyAdviceToMethod( + isMethod() + .and( + nameContains("notify") + .and(isPublic()) + .and(takesArgument(0, named("org.eclipse.jetty.client.Response")))), + JettyClient12ResponseListenersInstrumentation.class.getName() + + "$JettyHttpClient12RespListenersNotifyAdvice"); + + // for complete listeners + transformer.applyAdviceToMethod( + isMethod() + .and( + nameContains("notifyComplete") + .and(isPublic()) + .and(takesArgument(0, named("org.eclipse.jetty.client.Result")))), + JettyClient12ResponseListenersInstrumentation.class.getName() + + "$JettyHttpClient12CompleteListenersNotifyAdvice"); + } + + @SuppressWarnings("unused") + public static class JettyHttpClient12RespListenersNotifyAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnterNotify( + @Advice.Argument(0) Response response, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + context = (Context) response.getRequest().getAttributes().get(JETTY_CLIENT_CONTEXT_KEY); + if (context != null) { + scope = context.makeCurrent(); + } + } + + @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class) + public static void onExitNotify( + @Advice.Argument(0) Response response, + @Advice.Thrown Throwable throwable, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + + scope.close(); + } + } + + @SuppressWarnings("unused") + public static class JettyHttpClient12CompleteListenersNotifyAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnterComplete( + @Advice.Argument(0) Result result, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + context = (Context) result.getRequest().getAttributes().get(JETTY_CLIENT_CONTEXT_KEY); + if (context != null) { + scope = context.makeCurrent(); + } + } + + @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class) + public static void onExitComplete( + @Advice.Argument(0) Result result, + @Advice.Thrown Throwable throwable, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + + scope.close(); + } + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyHttpClient12Instrumentation.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyHttpClient12Instrumentation.java new file mode 100644 index 000000000000..9ba900164b36 --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyHttpClient12Instrumentation.java @@ -0,0 +1,107 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v12_0; + +import static io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v12_0.JettyHttpClientSingletons.JETTY_CLIENT_CONTEXT_KEY; +import static io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v12_0.JettyHttpClientSingletons.instrumenter; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.nameContains; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.jetty.httpclient.v12_0.internal.JettyClientTracingListener; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.eclipse.jetty.client.transport.HttpRequest; + +public class JettyHttpClient12Instrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("org.eclipse.jetty.client.transport.HttpRequest"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod() + .and(named("send")) + .and(takesArgument(0, named("org.eclipse.jetty.client.Response$CompleteListener"))), + JettyHttpClient12Instrumentation.class.getName() + "$JettyHttpClient12SendAdvice"); + // For request listeners + transformer.applyAdviceToMethod( + isMethod().and(nameContains("notify")), + JettyHttpClient12Instrumentation.class.getName() + "$JettyHttpClient12NotifyAdvice"); + } + + @SuppressWarnings("unused") + public static class JettyHttpClient12SendAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnterSend( + @Advice.This HttpRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + // start span + Context parentContext = Context.current(); + context = JettyClientTracingListener.handleRequest(parentContext, request, instrumenter()); + if (context == null) { + return; + } + // set context for responseListeners + request.attribute(JETTY_CLIENT_CONTEXT_KEY, parentContext); + + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class) + public static void onExitSend( + @Advice.This HttpRequest request, + @Advice.Thrown Throwable throwable, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + + // not ending span here unless error, span ended in the interceptor + scope.close(); + if (throwable != null) { + instrumenter().end(context, request, null, throwable); + } + } + } + + @SuppressWarnings("unused") + public static class JettyHttpClient12NotifyAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnterNotify( + @Advice.This HttpRequest request, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + context = (Context) request.getAttributes().get(JETTY_CLIENT_CONTEXT_KEY); + if (context == null) { + return; + } + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class) + public static void onExitNotify( + @Advice.Local("otelContext") Context context, @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + + scope.close(); + } + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyHttpClient12InstrumentationModule.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyHttpClient12InstrumentationModule.java new file mode 100644 index 000000000000..5d9690dbc7f4 --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyHttpClient12InstrumentationModule.java @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v12_0; + +import static java.util.Arrays.asList; + +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import java.util.List; + +@AutoService(InstrumentationModule.class) +public class JettyHttpClient12InstrumentationModule extends InstrumentationModule { + public JettyHttpClient12InstrumentationModule() { + super("jetty-httpclient", "jetty-httpclient-12.0"); + } + + @Override + public List typeInstrumentations() { + return asList( + new JettyHttpClient12Instrumentation(), + new JettyClient12ResponseListenersInstrumentation()); + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyHttpClientSingletons.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyHttpClientSingletons.java new file mode 100644 index 000000000000..68a9bca5adda --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyHttpClientSingletons.java @@ -0,0 +1,28 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v12_0; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.jetty.httpclient.v12_0.internal.JettyHttpClientInstrumenterBuilderFactory; +import io.opentelemetry.javaagent.bootstrap.internal.JavaagentHttpClientInstrumenters; +import org.eclipse.jetty.client.Request; +import org.eclipse.jetty.client.Response; + +public final class JettyHttpClientSingletons { + + static final String JETTY_CLIENT_CONTEXT_KEY = "otel-jetty-client-context"; + + private static final Instrumenter INSTRUMENTER = + JavaagentHttpClientInstrumenters.create( + JettyHttpClientInstrumenterBuilderFactory.create(GlobalOpenTelemetry.get())); + + public static Instrumenter instrumenter() { + return INSTRUMENTER; + } + + private JettyHttpClientSingletons() {} +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyHttpClient12AgentTest.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyHttpClient12AgentTest.java new file mode 100644 index 000000000000..7884e15938e7 --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jetty/httpclient/v12_0/JettyHttpClient12AgentTest.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v12_0; + +import io.opentelemetry.instrumentation.jetty.httpclient.v12_0.AbstractJettyClient12Test; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.junit.jupiter.api.extension.RegisterExtension; + +class JettyHttpClient12AgentTest extends AbstractJettyClient12Test { + + @RegisterExtension + static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent(); + + @Override + protected HttpClient createStandardClient() { + return new HttpClient(); + } + + @Override + protected HttpClient createHttpsClient(SslContextFactory.Client sslContextFactory) { + HttpClient httpClient = new HttpClient(); + httpClient.setSslContextFactory(sslContextFactory); + return httpClient; + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/build.gradle.kts b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/build.gradle.kts new file mode 100644 index 000000000000..da2df5c220a1 --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("otel.library-instrumentation") +} + +otelJava { + minJavaVersionSupported.set(JavaVersion.VERSION_17) +} + +dependencies { + library("org.eclipse.jetty:jetty-client:12.0.0") + + testImplementation(project(":instrumentation:jetty-httpclient::jetty-httpclient-12.0:testing")) +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/JettyClientTelemetry.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/JettyClientTelemetry.java new file mode 100644 index 000000000000..3e123801321a --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/JettyClientTelemetry.java @@ -0,0 +1,37 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jetty.httpclient.v12_0; + +import io.opentelemetry.api.OpenTelemetry; +import org.eclipse.jetty.client.HttpClient; + +/** Entrypoint for instrumenting Jetty client. */ +public final class JettyClientTelemetry { + + /** Returns a new {@link JettyClientTelemetry} configured with the given {@link OpenTelemetry}. */ + public static JettyClientTelemetry create(OpenTelemetry openTelemetry) { + JettyClientTelemetryBuilder builder = builder(openTelemetry); + return builder.build(); + } + + /** + * Returns a new {@link JettyClientTelemetryBuilder} configured with the given {@link + * OpenTelemetry}. + */ + public static JettyClientTelemetryBuilder builder(OpenTelemetry openTelemetry) { + return new JettyClientTelemetryBuilder(openTelemetry); + } + + private final HttpClient httpClient; + + JettyClientTelemetry(HttpClient httpClient) { + this.httpClient = httpClient; + } + + public HttpClient getHttpClient() { + return httpClient; + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/JettyClientTelemetryBuilder.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/JettyClientTelemetryBuilder.java new file mode 100644 index 000000000000..a914f73d266f --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/JettyClientTelemetryBuilder.java @@ -0,0 +1,131 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jetty.httpclient.v12_0; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import io.opentelemetry.instrumentation.jetty.httpclient.v12_0.internal.JettyHttpClientInstrumenterBuilderFactory; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import org.eclipse.jetty.client.HttpClientTransport; +import org.eclipse.jetty.client.Request; +import org.eclipse.jetty.client.Response; +import org.eclipse.jetty.util.ssl.SslContextFactory; + +public final class JettyClientTelemetryBuilder { + + private final DefaultHttpClientInstrumenterBuilder builder; + private HttpClientTransport httpClientTransport; + private SslContextFactory.Client sslContextFactory; + + JettyClientTelemetryBuilder(OpenTelemetry openTelemetry) { + builder = JettyHttpClientInstrumenterBuilderFactory.create(openTelemetry); + } + + @CanIgnoreReturnValue + public JettyClientTelemetryBuilder setHttpClientTransport( + HttpClientTransport httpClientTransport) { + this.httpClientTransport = httpClientTransport; + return this; + } + + @CanIgnoreReturnValue + public JettyClientTelemetryBuilder setSslContextFactory( + SslContextFactory.Client sslContextFactory) { + this.sslContextFactory = sslContextFactory; + return this; + } + + /** + * Adds an additional {@link AttributesExtractor} to invoke to set attributes to instrumented + * items. + */ + @CanIgnoreReturnValue + public JettyClientTelemetryBuilder addAttributeExtractor( + AttributesExtractor attributesExtractor) { + builder.addAttributeExtractor(attributesExtractor); + return this; + } + + /** + * Configures the HTTP request headers that will be captured as span attributes. + * + * @param requestHeaders A list of HTTP header names. + */ + @CanIgnoreReturnValue + public JettyClientTelemetryBuilder setCapturedRequestHeaders(List requestHeaders) { + builder.setCapturedRequestHeaders(requestHeaders); + return this; + } + + /** + * Configures the HTTP response headers that will be captured as span attributes. + * + * @param responseHeaders A list of HTTP header names. + */ + @CanIgnoreReturnValue + public JettyClientTelemetryBuilder setCapturedResponseHeaders(List responseHeaders) { + builder.setCapturedResponseHeaders(responseHeaders); + return this; + } + + /** + * Configures the instrumentation to recognize an alternative set of HTTP request methods. + * + *

By default, this instrumentation defines "known" methods as the ones listed in RFC9110 and the PATCH + * method defined in RFC5789. + * + *

Note: calling this method overrides the default known method sets completely; it does + * not supplement it. + * + * @param knownMethods A set of recognized HTTP request methods. + * @see HttpClientAttributesExtractorBuilder#setKnownMethods(Set) + */ + @CanIgnoreReturnValue + public JettyClientTelemetryBuilder setKnownMethods(Set knownMethods) { + builder.setKnownMethods(knownMethods); + return this; + } + + /** + * Configures the instrumentation to emit experimental HTTP client metrics. + * + * @param emitExperimentalHttpClientMetrics {@code true} if the experimental HTTP client metrics + * are to be emitted. + */ + @CanIgnoreReturnValue + public JettyClientTelemetryBuilder setEmitExperimentalHttpClientMetrics( + boolean emitExperimentalHttpClientMetrics) { + builder.setEmitExperimentalHttpClientMetrics(emitExperimentalHttpClientMetrics); + return this; + } + + /** Sets custom {@link SpanNameExtractor} via transform function. */ + @CanIgnoreReturnValue + public JettyClientTelemetryBuilder setSpanNameExtractor( + Function, ? extends SpanNameExtractor> + spanNameExtractorTransformer) { + builder.setSpanNameExtractor(spanNameExtractorTransformer); + return this; + } + + /** + * Returns a new {@link JettyClientTelemetry} with the settings of this {@link + * JettyClientTelemetryBuilder}. + */ + public JettyClientTelemetry build() { + TracingHttpClient tracingHttpClient = + TracingHttpClient.buildNew(builder.build(), sslContextFactory, httpClientTransport); + + return new JettyClientTelemetry(tracingHttpClient); + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/TracingHttpClient.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/TracingHttpClient.java new file mode 100644 index 000000000000..6507d00bd7dd --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/TracingHttpClient.java @@ -0,0 +1,60 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jetty.httpclient.v12_0; + +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import java.net.URI; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.HttpClientTransport; +import org.eclipse.jetty.client.Request; +import org.eclipse.jetty.client.Response; +import org.eclipse.jetty.client.transport.HttpConversation; +import org.eclipse.jetty.util.ssl.SslContextFactory; + +class TracingHttpClient extends HttpClient { + + private final Instrumenter instrumenter; + + TracingHttpClient(Instrumenter instrumenter) { + this.instrumenter = instrumenter; + } + + TracingHttpClient( + Instrumenter instrumenter, SslContextFactory.Client sslContextFactory) { + setSslContextFactory(sslContextFactory); + this.instrumenter = instrumenter; + } + + TracingHttpClient( + Instrumenter instrumenter, + HttpClientTransport transport, + SslContextFactory.Client sslContextFactory) { + super(transport); + setSslContextFactory(sslContextFactory); + this.instrumenter = instrumenter; + } + + static TracingHttpClient buildNew( + Instrumenter instrumenter, + SslContextFactory.Client sslContextFactory, + HttpClientTransport httpClientTransport) { + TracingHttpClient tracingHttpClient; + if (sslContextFactory != null && httpClientTransport != null) { + tracingHttpClient = + new TracingHttpClient(instrumenter, httpClientTransport, sslContextFactory); + } else if (sslContextFactory != null) { + tracingHttpClient = new TracingHttpClient(instrumenter, sslContextFactory); + } else { + tracingHttpClient = new TracingHttpClient(instrumenter); + } + return tracingHttpClient; + } + + @Override + public Request newRequest(URI uri) { + return new TracingHttpRequest(this, new HttpConversation(), uri, instrumenter); + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/TracingHttpRequest.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/TracingHttpRequest.java new file mode 100644 index 000000000000..9bdc687c250d --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/TracingHttpRequest.java @@ -0,0 +1,99 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jetty.httpclient.v12_0; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.jetty.httpclient.v12_0.internal.JettyClientTracingListener; +import java.net.URI; +import java.nio.ByteBuffer; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.Request; +import org.eclipse.jetty.client.Response; +import org.eclipse.jetty.client.transport.HttpConversation; +import org.eclipse.jetty.client.transport.HttpRequest; + +class TracingHttpRequest extends HttpRequest { + + private final Instrumenter instrumenter; + private Context parentContext; + + public TracingHttpRequest( + HttpClient client, + HttpConversation conversation, + URI uri, + Instrumenter instrumenter) { + super(client, conversation, uri); + this.instrumenter = instrumenter; + } + + @Override + public void send(Response.CompleteListener listener) { + parentContext = Context.current(); + // start span and attach listeners. + JettyClientTracingListener.handleRequest(parentContext, this, instrumenter); + super.send( + result -> { + try (Scope scope = openScope()) { + listener.onComplete(result); + } + }); + } + + private Scope openScope() { + return parentContext != null ? parentContext.makeCurrent() : null; + } + + @Override + public void notifyQueued() { + try (Scope scope = openScope()) { + super.notifyQueued(); + } + } + + @Override + public void notifyBegin() { + try (Scope scope = openScope()) { + super.notifyBegin(); + } + } + + @Override + public void notifyHeaders() { + try (Scope scope = openScope()) { + super.notifyHeaders(); + } + } + + @Override + public void notifyCommit() { + try (Scope scope = openScope()) { + super.notifyCommit(); + } + } + + @Override + public void notifyContent(ByteBuffer byteBuffer) { + try (Scope scope = openScope()) { + super.notifyContent(byteBuffer); + } + } + + @Override + public void notifySuccess() { + try (Scope scope = openScope()) { + super.notifySuccess(); + } + } + + @Override + public void notifyFailure(Throwable failure) { + try (Scope scope = openScope()) { + super.notifyFailure(failure); + } + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/HttpHeaderSetter.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/HttpHeaderSetter.java new file mode 100644 index 000000000000..b094abd3a4dc --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/HttpHeaderSetter.java @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jetty.httpclient.v12_0.internal; + +import io.opentelemetry.context.propagation.TextMapSetter; +import org.eclipse.jetty.client.Request; +import org.eclipse.jetty.http.HttpField; + +enum HttpHeaderSetter implements TextMapSetter { + INSTANCE; + + @Override + public void set(Request request, String key, String value) { + if (request != null) { + request.headers( + httpFields -> { + httpFields.put(new HttpField(key, value)); + }); + } + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/JettyClientHttpAttributesGetter.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/JettyClientHttpAttributesGetter.java new file mode 100644 index 000000000000..6a241120fd55 --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/JettyClientHttpAttributesGetter.java @@ -0,0 +1,84 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jetty.httpclient.v12_0.internal; + +import io.opentelemetry.instrumentation.api.internal.HttpProtocolUtil; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter; +import java.util.List; +import javax.annotation.Nullable; +import org.eclipse.jetty.client.Request; +import org.eclipse.jetty.client.Response; +import org.eclipse.jetty.http.HttpVersion; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public enum JettyClientHttpAttributesGetter + implements HttpClientAttributesGetter { + INSTANCE; + + @Override + @Nullable + public String getHttpRequestMethod(Request request) { + return request.getMethod(); + } + + @Override + @Nullable + public String getUrlFull(Request request) { + return request.getURI().toString(); + } + + @Override + public List getHttpRequestHeader(Request request, String name) { + return request.getHeaders().getValuesList(name); + } + + @Override + public Integer getHttpResponseStatusCode( + Request request, Response response, @Nullable Throwable error) { + return response.getStatus(); + } + + @Override + public List getHttpResponseHeader(Request request, Response response, String name) { + return response.getHeaders().getValuesList(name); + } + + @Nullable + @Override + public String getNetworkProtocolName(Request request, @Nullable Response response) { + return "http"; + } + + @Nullable + @Override + public String getNetworkProtocolVersion(Request request, @Nullable Response response) { + HttpVersion httpVersion = null; + if (response != null) { + httpVersion = response.getVersion(); + } + if (httpVersion == null) { + httpVersion = request.getVersion(); + } + if (httpVersion == null) { + return null; + } + return HttpProtocolUtil.getVersion(httpVersion.toString()); + } + + @Override + @Nullable + public String getServerAddress(Request request) { + return request.getHost(); + } + + @Override + public Integer getServerPort(Request request) { + return request.getPort(); + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/JettyClientTracingListener.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/JettyClientTracingListener.java new file mode 100644 index 000000000000..be20a319a1cc --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/JettyClientTracingListener.java @@ -0,0 +1,63 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jetty.httpclient.v12_0.internal; + +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import javax.annotation.Nullable; +import org.eclipse.jetty.client.Request; +import org.eclipse.jetty.client.Response; + +/** + * JettyClientTracingListener performs two actions when {@link #handleRequest(Context, Request, + * Instrumenter)} is called 1. Start the CLIENT span 2. Set the listener callbacks for each + * lifecycle action that signal end of the request. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class JettyClientTracingListener + implements Request.FailureListener, Response.SuccessListener, Response.FailureListener { + + private final Context context; + + private final Instrumenter instrumenter; + + private JettyClientTracingListener( + Context context, Instrumenter instrumenter) { + this.context = context; + this.instrumenter = instrumenter; + } + + @Nullable + public static Context handleRequest( + Context parentContext, Request jettyRequest, Instrumenter instrumenter) { + if (!instrumenter.shouldStart(parentContext, jettyRequest)) { + return null; + } + + Context context = instrumenter.start(parentContext, jettyRequest); + + JettyClientTracingListener listener = new JettyClientTracingListener(context, instrumenter); + jettyRequest.onRequestFailure(listener).onResponseFailure(listener).onResponseSuccess(listener); + return context; + } + + @Override + public void onFailure(Response response, Throwable t) { + instrumenter.end(this.context, response.getRequest(), response, t); + } + + @Override + public void onFailure(Request request, Throwable t) { + instrumenter.end(this.context, request, null, t); + } + + @Override + public void onSuccess(Response response) { + instrumenter.end(this.context, response.getRequest(), response, null); + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/JettyHttpClientInstrumenterBuilderFactory.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/JettyHttpClientInstrumenterBuilderFactory.java new file mode 100644 index 000000000000..386a5e6c816b --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/internal/JettyHttpClientInstrumenterBuilderFactory.java @@ -0,0 +1,28 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jetty.httpclient.v12_0.internal; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.builder.internal.DefaultHttpClientInstrumenterBuilder; +import org.eclipse.jetty.client.Request; +import org.eclipse.jetty.client.Response; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public class JettyHttpClientInstrumenterBuilderFactory { + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.jetty-httpclient-12.0"; + + private JettyHttpClientInstrumenterBuilderFactory() {} + + public static DefaultHttpClientInstrumenterBuilder create( + OpenTelemetry openTelemetry) { + return new DefaultHttpClientInstrumenterBuilder<>( + INSTRUMENTATION_NAME, openTelemetry, JettyClientHttpAttributesGetter.INSTANCE) + .setHeaderSetter(HttpHeaderSetter.INSTANCE); + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/test/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/JettyHttpClient12LibraryTest.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/test/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/JettyHttpClient12LibraryTest.java new file mode 100644 index 000000000000..e7cf65fb206d --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/library/src/test/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/JettyHttpClient12LibraryTest.java @@ -0,0 +1,39 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jetty.httpclient.v12_0; + +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest; +import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension; +import java.util.Collections; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.junit.jupiter.api.extension.RegisterExtension; + +class JettyHttpClient12LibraryTest extends AbstractJettyClient12Test { + + @RegisterExtension + static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forLibrary(); + + @Override + protected HttpClient createStandardClient() { + return JettyClientTelemetry.builder(testing.getOpenTelemetry()) + .setCapturedRequestHeaders( + Collections.singletonList(AbstractHttpClientTest.TEST_REQUEST_HEADER)) + .setCapturedResponseHeaders( + Collections.singletonList(AbstractHttpClientTest.TEST_RESPONSE_HEADER)) + .build() + .getHttpClient(); + } + + @Override + protected HttpClient createHttpsClient(SslContextFactory.Client sslContextFactory) { + return JettyClientTelemetry.builder(testing.getOpenTelemetry()) + .setSslContextFactory(sslContextFactory) + .build() + .getHttpClient(); + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/testing/build.gradle.kts b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/testing/build.gradle.kts new file mode 100644 index 000000000000..6205a47c0461 --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/testing/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("otel.java-conventions") +} + +dependencies { + api(project(":testing-common")) + + api("org.eclipse.jetty:jetty-client:12.0.0") + + implementation("io.opentelemetry:opentelemetry-api") +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-12.0/testing/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/AbstractJettyClient12Test.java b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/testing/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/AbstractJettyClient12Test.java new file mode 100644 index 000000000000..4f606242c9da --- /dev/null +++ b/instrumentation/jetty-httpclient/jetty-httpclient-12.0/testing/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v12_0/AbstractJettyClient12Test.java @@ -0,0 +1,122 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.jetty.httpclient.v12_0; + +import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest; +import io.opentelemetry.instrumentation.testing.junit.http.HttpClientResult; +import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions; +import java.net.URI; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.eclipse.jetty.client.ContentResponse; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.Request; +import org.eclipse.jetty.client.Response; +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +public abstract class AbstractJettyClient12Test extends AbstractHttpClientTest { + + protected abstract HttpClient createStandardClient(); + + protected abstract HttpClient createHttpsClient(SslContextFactory.Client sslContextFactory); + + protected HttpClient client = createStandardClient(); + protected HttpClient httpsClient; + + @BeforeEach + public void before() throws Exception { + client.setConnectTimeout(CONNECTION_TIMEOUT.toMillis()); + client.start(); + + SslContextFactory.Client tlsCtx = new SslContextFactory.Client(); + httpsClient = createHttpsClient(tlsCtx); + httpsClient.setFollowRedirects(false); + httpsClient.start(); + } + + @AfterEach + public void after() throws Exception { + client.stop(); + httpsClient.stop(); + } + + @Override + protected void configure(HttpClientTestOptions.Builder optionsBuilder) { + // disable redirect tests + optionsBuilder.disableTestRedirects(); + // jetty 12 does not support to reuse request + // use request.send() twice will block the program infinitely + optionsBuilder.disableTestReusedRequest(); + } + + @Override + public Request buildRequest(String method, URI uri, Map headers) { + HttpClient theClient = Objects.equals(uri.getScheme(), "https") ? httpsClient : client; + + Request request = theClient.newRequest(uri); + request.agent("Jetty"); + + request.method(method); + request.timeout(READ_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS); + + return request; + } + + @Override + public int sendRequest(Request request, String method, URI uri, Map headers) + throws ExecutionException, InterruptedException, TimeoutException { + headers.forEach((k, v) -> request.headers(httpFields -> httpFields.put(new HttpField(k, v)))); + + ContentResponse response = request.send(); + + return response.getStatus(); + } + + @Override + public void sendRequestWithCallback( + Request request, + String method, + URI uri, + Map headers, + HttpClientResult requestResult) { + JettyClientListener clientListener = new JettyClientListener(); + + request.onRequestFailure(clientListener); + request.onResponseFailure(clientListener); + headers.forEach((k, v) -> request.headers(httpFields -> httpFields.put(new HttpField(k, v)))); + + request.send( + result -> { + if (clientListener.failure != null) { + requestResult.complete(clientListener.failure); + return; + } + + requestResult.complete(result.getResponse().getStatus()); + }); + } + + private static class JettyClientListener + implements Request.FailureListener, Response.FailureListener { + volatile Throwable failure; + + @Override + public void onFailure(Request request, Throwable failure) { + this.failure = failure; + } + + @Override + public void onFailure(Response response, Throwable failure) { + this.failure = failure; + } + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/javaagent/build.gradle.kts b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/javaagent/build.gradle.kts index 00e213117361..71d9062f5375 100644 --- a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/javaagent/build.gradle.kts +++ b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/javaagent/build.gradle.kts @@ -18,6 +18,8 @@ dependencies { library("org.eclipse.jetty:jetty-client:$jettyVers_base9") + testInstrumentation(project(":instrumentation:jetty-httpclient:jetty-httpclient-12.0:javaagent")) + testImplementation(project(":instrumentation:jetty-httpclient:jetty-httpclient-9.2:testing")) latestDepTestLibrary("org.eclipse.jetty:jetty-client:9.+") // documented limitation diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/TracingHttpClient.java b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/TracingHttpClient.java index e89708a146e9..ffa837707f44 100644 --- a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/TracingHttpClient.java +++ b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/TracingHttpClient.java @@ -23,7 +23,6 @@ class TracingHttpClient extends HttpClient { private final Instrumenter instrumenter; TracingHttpClient(Instrumenter instrumenter) { - super(); this.instrumenter = instrumenter; } diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/JettyClientHttpAttributesGetter.java b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/JettyClientHttpAttributesGetter.java index 35212089eaf6..75609b760582 100644 --- a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/JettyClientHttpAttributesGetter.java +++ b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/JettyClientHttpAttributesGetter.java @@ -5,6 +5,7 @@ package io.opentelemetry.instrumentation.jetty.httpclient.v9_2.internal; +import io.opentelemetry.instrumentation.api.internal.HttpProtocolUtil; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter; import java.util.List; import javax.annotation.Nullable; @@ -67,11 +68,7 @@ public String getNetworkProtocolVersion(Request request, @Nullable Response resp if (httpVersion == null) { return null; } - String version = httpVersion.toString(); - if (version.startsWith("HTTP/")) { - version = version.substring("HTTP/".length()); - } - return version; + return HttpProtocolUtil.getVersion(httpVersion.toString()); } @Override diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/JettyClientTracingListener.java b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/JettyClientTracingListener.java index 844929afe81b..71909ac0557e 100644 --- a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/JettyClientTracingListener.java +++ b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/internal/JettyClientTracingListener.java @@ -29,10 +29,7 @@ * at any time. */ public final class JettyClientTracingListener - implements Request.BeginListener, - Request.FailureListener, - Response.SuccessListener, - Response.FailureListener { + implements Request.FailureListener, Response.SuccessListener, Response.FailureListener { private static final Logger logger = Logger.getLogger(JettyClientTracingListener.class.getName()); @@ -77,11 +74,7 @@ public static Context handleRequest( wrapRequestListeners(existingListeners, context); JettyClientTracingListener listener = new JettyClientTracingListener(context, instrumenter); - request - .onRequestBegin(listener) - .onRequestFailure(listener) - .onResponseFailure(listener) - .onResponseSuccess(listener); + request.onRequestFailure(listener).onResponseFailure(listener).onResponseSuccess(listener); return context; } @@ -123,9 +116,6 @@ private static void wrapRequestListeners( } } - @Override - public void onBegin(Request request) {} - @Override public void onSuccess(Response response) { instrumenter.end(this.context, response.getRequest(), response, null); diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/testing/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/AbstractJettyClient9Test.java b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/testing/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/AbstractJettyClient9Test.java index 7099694776ef..9a53e6014e7a 100644 --- a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/testing/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/AbstractJettyClient9Test.java +++ b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/testing/src/main/java/io/opentelemetry/instrumentation/jetty/httpclient/v9_2/AbstractJettyClient9Test.java @@ -19,7 +19,9 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInstance; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public abstract class AbstractJettyClient9Test extends AbstractHttpClientTest { private HttpClient client; diff --git a/settings.gradle.kts b/settings.gradle.kts index dbdf71f92319..7e766690e28c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -357,6 +357,9 @@ include(":instrumentation:jetty:jetty-common:javaagent") include(":instrumentation:jetty-httpclient:jetty-httpclient-9.2:javaagent") include(":instrumentation:jetty-httpclient:jetty-httpclient-9.2:library") include(":instrumentation:jetty-httpclient:jetty-httpclient-9.2:testing") +include(":instrumentation:jetty-httpclient:jetty-httpclient-12.0:javaagent") +include(":instrumentation:jetty-httpclient:jetty-httpclient-12.0:library") +include(":instrumentation:jetty-httpclient:jetty-httpclient-12.0:testing") include(":instrumentation:jms:jms-1.1:javaagent") include(":instrumentation:jms:jms-3.0:javaagent") include(":instrumentation:jms:jms-common:bootstrap")