Skip to content

Commit 60c7993

Browse files
authored
Fix instrumentation for ibm https url connection connect (#13728)
1 parent ba0478e commit 60c7993

File tree

5 files changed

+137
-6
lines changed

5 files changed

+137
-6
lines changed

instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentation.java

Lines changed: 8 additions & 6 deletions
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.instrumentation.httpurlconnection.HttpUrlConnectionSingletons.instrumenter;
11-
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
11+
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
1212
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
1313
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
1414
import static net.bytebuddy.matcher.ElementMatchers.named;
@@ -25,16 +25,15 @@
2525
import net.bytebuddy.asm.Advice;
2626
import net.bytebuddy.description.type.TypeDescription;
2727
import net.bytebuddy.matcher.ElementMatcher;
28-
import net.bytebuddy.matcher.ElementMatchers;
2928

3029
public class HttpUrlConnectionInstrumentation implements TypeInstrumentation {
3130
@Override
3231
public ElementMatcher<TypeDescription> typeMatcher() {
3332
return nameStartsWith("java.net.")
34-
.or(ElementMatchers.<TypeDescription>nameStartsWith("sun.net"))
33+
.or(nameStartsWith("sun.net"))
3534
// In WebLogic, URL.openConnection() returns its own internal implementation of
3635
// HttpURLConnection, which does not delegate the methods that have to be instrumented to
37-
// the JDK superclass. Therefore it needs to be instrumented directly.
36+
// the JDK superclass. Therefore, it needs to be instrumented directly.
3837
.or(named("weblogic.net.http.HttpURLConnection"))
3938
// This class is a simple delegator. Skip because it does not update its `connected`
4039
// field.
@@ -45,10 +44,13 @@ public ElementMatcher<TypeDescription> typeMatcher() {
4544
@Override
4645
public void transform(TypeTransformer transformer) {
4746
transformer.applyAdviceToMethod(
48-
isMethod().and(isPublic()).and(namedOneOf("connect", "getOutputStream", "getInputStream")),
47+
isPublic()
48+
.and(namedOneOf("connect", "getOutputStream", "getInputStream"))
49+
// ibm https url connection does not delegate connect, it calls plainConnect instead
50+
.or(isProtected().and(named("plainConnect"))),
4951
this.getClass().getName() + "$HttpUrlConnectionAdvice");
5052
transformer.applyAdviceToMethod(
51-
isMethod().and(isPublic()).and(named("getResponseCode")),
53+
isPublic().and(named("getResponseCode")),
5254
this.getClass().getName() + "$GetResponseCodeAdvice");
5355
}
5456

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.smoketest
7+
8+
import io.opentelemetry.proto.trace.v1.Span
9+
import org.slf4j.Logger
10+
import org.slf4j.LoggerFactory
11+
import org.testcontainers.containers.Container
12+
import org.testcontainers.containers.GenericContainer
13+
import org.testcontainers.containers.Network
14+
import org.testcontainers.containers.output.Slf4jLogConsumer
15+
import org.testcontainers.containers.wait.strategy.Wait
16+
import org.testcontainers.utility.DockerImageName
17+
import org.testcontainers.utility.MountableFile
18+
import spock.lang.IgnoreIf
19+
import spock.lang.Specification
20+
21+
import java.time.Duration
22+
23+
import static io.opentelemetry.smoketest.TestContainerManager.useWindowsContainers
24+
25+
@IgnoreIf({ useWindowsContainers() })
26+
class IbmHttpsUrlConnectionTest extends Specification {
27+
private static final Logger logger = LoggerFactory.getLogger(IbmHttpsUrlConnectionTest)
28+
29+
private static final String TARGET_AGENT_FILENAME = "opentelemetry-javaagent.jar"
30+
private static final String agentPath = System.getProperty("io.opentelemetry.smoketest.agent.shadowJar.path")
31+
private static final int BACKEND_PORT = 8080
32+
private static final String BACKEND_ALIAS = "backend"
33+
34+
private final Network network = Network.newNetwork()
35+
36+
def "test https url connection"() {
37+
setup:
38+
GenericContainer backend =
39+
new GenericContainer<>(
40+
DockerImageName.parse(
41+
"ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-fake-backend:20221127.3559314891"))
42+
.withExposedPorts(BACKEND_PORT)
43+
.withEnv("JAVA_TOOL_OPTIONS", "-Xmx128m")
44+
.waitingFor(Wait.forHttp("/health").forPort(BACKEND_PORT))
45+
.withNetwork(network)
46+
.withNetworkAliases(BACKEND_ALIAS)
47+
.withLogConsumer(new Slf4jLogConsumer(logger))
48+
backend.start()
49+
50+
def telemetryRetriever = new TelemetryRetriever(backend.getMappedPort(BACKEND_PORT))
51+
52+
GenericContainer target =
53+
new GenericContainer<>(DockerImageName.parse("ibmjava:8-sdk"))
54+
.withStartupTimeout(Duration.ofMinutes(5))
55+
.withNetwork(network)
56+
.withLogConsumer(new Slf4jLogConsumer(logger))
57+
.withCopyFileToContainer(
58+
MountableFile.forHostPath(agentPath), "/" + TARGET_AGENT_FILENAME)
59+
.withCopyFileToContainer(
60+
MountableFile.forClasspathResource("ibmhttpsurlconnection/IbmHttpsUrlConnectionTest.java"), "/IbmHttpsUrlConnectionTest.java")
61+
.withCopyFileToContainer(
62+
MountableFile.forClasspathResource("ibmhttpsurlconnection/start.sh", 777), "/start.sh")
63+
.withCopyFileToContainer(
64+
MountableFile.forClasspathResource("ibmhttpsurlconnection/test.sh", 777), "/test.sh")
65+
.waitingFor(
66+
Wait.forLogMessage(".*started.*\\n", 1)
67+
)
68+
.withCommand("/bin/sh", "-c", "/start.sh")
69+
target.start()
70+
71+
when:
72+
Container.ExecResult result = target.execInContainer("/bin/sh", "-c", "/test.sh")
73+
then:
74+
result.getExitCode() == 0
75+
76+
TraceInspector traces = new TraceInspector(telemetryRetriever.waitForTraces())
77+
Set<String> traceIds = traces.traceIds
78+
79+
then: "There is one trace"
80+
traceIds.size() == 1
81+
82+
and: "Client span in the distributed trace"
83+
traces.countSpansByKind(Span.SpanKind.SPAN_KIND_CLIENT) == 1
84+
85+
and: "Expected span names"
86+
traces.countSpansByName("GET") == 1
87+
88+
cleanup:
89+
System.err.println(result.toString())
90+
target.stop()
91+
backend.stop()
92+
}
93+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import java.io.InputStream;
7+
import java.net.HttpURLConnection;
8+
import java.net.URL;
9+
10+
public class IbmHttpsUrlConnectionTest {
11+
12+
public static void main(String... args) throws Exception {
13+
HttpURLConnection connection =
14+
(HttpURLConnection) new URL("https://google.com").openConnection();
15+
connection.connect();
16+
InputStream stream = connection.getInputStream();
17+
stream.close();
18+
}
19+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash -e
2+
3+
echo "started"
4+
while :
5+
do
6+
sleep 1
7+
done
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash -e
2+
3+
echo "compiling"
4+
javac IbmHttpsUrlConnectionTest.java
5+
echo "finish compiling"
6+
echo "executing"
7+
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
8+
export OTEL_EXPORTER_OTLP_ENDPOINT=http://backend:8080
9+
export OTEL_JAVAAGENT_DEBUG=true
10+
java -javaagent:opentelemetry-javaagent.jar IbmHttpsUrlConnectionTest

0 commit comments

Comments
 (0)