Skip to content

Commit 08236a7

Browse files
laurittrask
andauthored
Add library instrumentation for java http client (open-telemetry#8138)
Resolves open-telemetry#8069 The javaagent instrumentation also supports propagating context into [BodyHandler](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpResponse.BodyHandler.html) implemented in https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/java-http-client/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/BodyHandlerWrapper.java I think the initial idea behind it was that this allowed propagating context into callbacks. Because this didn't work for `connectionErrorUnopenedPortWithCallback` test later we also added wrapping completable future to take care of propagating context into callbacks. Should I also implement context propagation for `BodyHandler` in library instrumentation or should I just delete it? I guess it could come handy if someone builds a custom `BodyHandler` and wants to emit spans from there, though this doesn't feel too likely. I'd like deleting it more. --------- Co-authored-by: Trask Stalnaker <[email protected]>
1 parent eb83b21 commit 08236a7

27 files changed

+673
-256
lines changed

docs/supported-libraries.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ These are the supported libraries and frameworks:
6868
| [HttpURLConnection](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/HttpURLConnection.html) | Java 8+ | N/A | [HTTP Client Spans], [HTTP Client Metrics] |
6969
| [Hystrix](https://github.com/Netflix/Hystrix) | 1.4+ | N/A | none |
7070
| [Java Executors](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html) | Java 8+ | N/A | Context propagation |
71-
| [Java Http Client](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/package-summary.html) | Java 11+ | N/A | [HTTP Client Spans], [HTTP Client Metrics] |
71+
| [Java Http Client](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/package-summary.html) | Java 11+ | [opentelemetry-java-http-client](../instrumentation/java-http-client/library) | [HTTP Client Spans], [HTTP Client Metrics] |
7272
| [java.util.logging](https://docs.oracle.com/javase/8/docs/api/java/util/logging/package-summary.html) | Java 8+ | N/A | none |
7373
| [Java Platform](https://docs.oracle.com/javase/8/docs/api/java/lang/management/ManagementFactory.html) | Java 8+ | [opentelemetry-runtime-metrics](../instrumentation/runtime-metrics/library),<br>[opentelemetry-resources](../instrumentation/resources/library) | [JVM Runtime Metrics] |
7474
| [JAX-RS](https://javaee.github.io/javaee-spec/javadocs/javax/ws/rs/package-summary.html) | 0.5+ | N/A | Provides `http.route` [2], Controller Spans [3] |

instrumentation/java-http-client/javaagent/build.gradle.kts

+5
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,8 @@ muzzle {
1111
otelJava {
1212
minJavaVersionSupported.set(JavaVersion.VERSION_11)
1313
}
14+
15+
dependencies {
16+
implementation(project(":instrumentation:java-http-client:library"))
17+
testImplementation(project(":instrumentation:java-http-client:testing"))
18+
}

instrumentation/java-http-client/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/BodyHandlerWrapper.java

-80
This file was deleted.

instrumentation/java-http-client/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/HttpClientInstrumentation.java

+5-8
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
99
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass;
1010
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
11-
import static io.opentelemetry.javaagent.instrumentation.httpclient.JdkHttpClientSingletons.instrumenter;
11+
import static io.opentelemetry.javaagent.instrumentation.httpclient.JavaHttpClientSingletons.instrumenter;
1212
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
1313
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
1414
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
@@ -19,6 +19,8 @@
1919

2020
import io.opentelemetry.context.Context;
2121
import io.opentelemetry.context.Scope;
22+
import io.opentelemetry.instrumentation.httpclient.internal.CompletableFutureWrapper;
23+
import io.opentelemetry.instrumentation.httpclient.internal.ResponseConsumer;
2224
import io.opentelemetry.javaagent.bootstrap.CallDepth;
2325
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
2426
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
@@ -59,8 +61,7 @@ public void transform(TypeTransformer transformer) {
5961
isMethod()
6062
.and(named("sendAsync"))
6163
.and(isPublic())
62-
.and(takesArgument(0, named("java.net.http.HttpRequest")))
63-
.and(takesArgument(1, named("java.net.http.HttpResponse$BodyHandler"))),
64+
.and(takesArgument(0, named("java.net.http.HttpRequest"))),
6465
HttpClientInstrumentation.class.getName() + "$SendAsyncAdvice");
6566
}
6667

@@ -103,7 +104,6 @@ public static class SendAsyncAdvice {
103104
@Advice.OnMethodEnter(suppress = Throwable.class)
104105
public static void methodEnter(
105106
@Advice.Argument(value = 0) HttpRequest httpRequest,
106-
@Advice.Argument(value = 1, readOnly = false) HttpResponse.BodyHandler<?> bodyHandler,
107107
@Advice.Local("otelCallDepth") CallDepth callDepth,
108108
@Advice.Local("otelContext") Context context,
109109
@Advice.Local("otelParentContext") Context parentContext,
@@ -114,9 +114,6 @@ public static void methodEnter(
114114
}
115115

116116
parentContext = currentContext();
117-
if (bodyHandler != null) {
118-
bodyHandler = new BodyHandlerWrapper<>(bodyHandler, parentContext);
119-
}
120117
if (!instrumenter().shouldStart(parentContext, httpRequest)) {
121118
return;
122119
}
@@ -146,7 +143,7 @@ public static void methodExit(
146143
if (throwable != null) {
147144
instrumenter().end(context, httpRequest, null, throwable);
148145
} else {
149-
future = future.whenComplete(new ResponseConsumer(context, httpRequest));
146+
future = future.whenComplete(new ResponseConsumer(instrumenter(), context, httpRequest));
150147
future = CompletableFutureWrapper.wrap(future, parentContext);
151148
}
152149
}

instrumentation/java-http-client/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/HttpClientInstrumentationModule.java

+1-4
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ public HttpClientInstrumentationModule() {
2020

2121
@Override
2222
public List<TypeInstrumentation> typeInstrumentations() {
23-
return asList(
24-
new HttpClientInstrumentation(),
25-
new HttpHeadersInstrumentation(),
26-
new TrustedSubscriberInstrumentation());
23+
return asList(new HttpClientInstrumentation(), new HttpHeadersInstrumentation());
2724
}
2825
}

instrumentation/java-http-client/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/HttpHeadersInstrumentation.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
package io.opentelemetry.javaagent.instrumentation.httpclient;
77

88
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass;
9-
import static io.opentelemetry.javaagent.instrumentation.httpclient.JdkHttpClientSingletons.setter;
9+
import static io.opentelemetry.javaagent.instrumentation.httpclient.JavaHttpClientSingletons.setter;
1010
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
1111
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
1212
import static net.bytebuddy.matcher.ElementMatchers.named;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.httpclient;
7+
8+
import io.opentelemetry.api.GlobalOpenTelemetry;
9+
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
10+
import io.opentelemetry.instrumentation.api.instrumenter.net.PeerServiceAttributesExtractor;
11+
import io.opentelemetry.instrumentation.httpclient.internal.HttpHeadersSetter;
12+
import io.opentelemetry.instrumentation.httpclient.internal.JavaHttpClientInstrumenterFactory;
13+
import io.opentelemetry.instrumentation.httpclient.internal.JavaHttpClientNetAttributesGetter;
14+
import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig;
15+
import java.net.http.HttpRequest;
16+
import java.net.http.HttpResponse;
17+
import java.util.Arrays;
18+
19+
public class JavaHttpClientSingletons {
20+
21+
private static final HttpHeadersSetter SETTER;
22+
private static final Instrumenter<HttpRequest, HttpResponse<?>> INSTRUMENTER;
23+
24+
static {
25+
SETTER = new HttpHeadersSetter(GlobalOpenTelemetry.getPropagators());
26+
27+
JavaHttpClientNetAttributesGetter netAttributesGetter = new JavaHttpClientNetAttributesGetter();
28+
29+
INSTRUMENTER =
30+
JavaHttpClientInstrumenterFactory.createInstrumenter(
31+
GlobalOpenTelemetry.get(),
32+
CommonConfig.get().getClientRequestHeaders(),
33+
CommonConfig.get().getClientResponseHeaders(),
34+
Arrays.asList(
35+
PeerServiceAttributesExtractor.create(
36+
netAttributesGetter, CommonConfig.get().getPeerServiceMapping())));
37+
}
38+
39+
public static Instrumenter<HttpRequest, HttpResponse<?>> instrumenter() {
40+
return INSTRUMENTER;
41+
}
42+
43+
public static HttpHeadersSetter setter() {
44+
return SETTER;
45+
}
46+
47+
private JavaHttpClientSingletons() {}
48+
}

instrumentation/java-http-client/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/JdkHttpClientSingletons.java

-57
This file was deleted.

instrumentation/java-http-client/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/ResponseConsumer.java

-28
This file was deleted.

instrumentation/java-http-client/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpclient/TrustedSubscriberInstrumentation.java

-45
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.httpclient;
7+
8+
import io.opentelemetry.instrumentation.httpclient.AbstractJavaHttpClientTest;
9+
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
10+
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension;
11+
import java.net.http.HttpClient;
12+
import org.junit.jupiter.api.extension.RegisterExtension;
13+
14+
public class JavaHttpClientTest extends AbstractJavaHttpClientTest {
15+
16+
@RegisterExtension
17+
static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent();
18+
19+
@Override
20+
protected HttpClient configureHttpClient(HttpClient httpClient) {
21+
return httpClient;
22+
}
23+
}

0 commit comments

Comments
 (0)