Skip to content

Commit 8a3f1eb

Browse files
Add agent instrumentation for Ratpack 1.7+ (#12572)
1 parent 11773aa commit 8a3f1eb

File tree

36 files changed

+831
-124
lines changed

36 files changed

+831
-124
lines changed

instrumentation/ratpack/ratpack-1.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/ratpack/RatpackForkedHttpClientTest.java

-16
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,13 @@
55

66
package io.opentelemetry.javaagent.instrumentation.ratpack;
77

8-
import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
9-
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
10-
11-
import io.opentelemetry.api.common.AttributeKey;
128
import io.opentelemetry.instrumentation.ratpack.client.AbstractRatpackForkedHttpClientTest;
139
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
1410
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension;
15-
import java.net.URI;
16-
import java.util.HashSet;
17-
import java.util.Set;
1811
import org.junit.jupiter.api.extension.RegisterExtension;
1912

2013
class RatpackForkedHttpClientTest extends AbstractRatpackForkedHttpClientTest {
2114

2215
@RegisterExtension
2316
static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent();
24-
25-
@Override
26-
protected Set<AttributeKey<?>> computeHttpAttributes(URI uri) {
27-
Set<AttributeKey<?>> attributes = new HashSet<>(super.computeHttpAttributes(uri));
28-
// underlying netty instrumentation does not provide these
29-
attributes.remove(SERVER_ADDRESS);
30-
attributes.remove(SERVER_PORT);
31-
return attributes;
32-
}
3317
}

instrumentation/ratpack/ratpack-1.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/ratpack/RatpackHttpClientTest.java

-16
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,13 @@
55

66
package io.opentelemetry.javaagent.instrumentation.ratpack;
77

8-
import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
9-
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
10-
11-
import io.opentelemetry.api.common.AttributeKey;
128
import io.opentelemetry.instrumentation.ratpack.client.AbstractRatpackHttpClientTest;
139
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
1410
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension;
15-
import java.net.URI;
16-
import java.util.HashSet;
17-
import java.util.Set;
1811
import org.junit.jupiter.api.extension.RegisterExtension;
1912

2013
class RatpackHttpClientTest extends AbstractRatpackHttpClientTest {
2114

2215
@RegisterExtension
2316
static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent();
24-
25-
@Override
26-
protected Set<AttributeKey<?>> computeHttpAttributes(URI uri) {
27-
Set<AttributeKey<?>> attributes = new HashSet<>(super.computeHttpAttributes(uri));
28-
// underlying netty instrumentation does not provide these
29-
attributes.remove(SERVER_ADDRESS);
30-
attributes.remove(SERVER_PORT);
31-
return attributes;
32-
}
3317
}

instrumentation/ratpack/ratpack-1.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/ratpack/RatpackPooledHttpClientTest.java

-16
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,13 @@
55

66
package io.opentelemetry.javaagent.instrumentation.ratpack;
77

8-
import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
9-
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
10-
11-
import io.opentelemetry.api.common.AttributeKey;
128
import io.opentelemetry.instrumentation.ratpack.client.AbstractRatpackPooledHttpClientTest;
139
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
1410
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension;
15-
import java.net.URI;
16-
import java.util.HashSet;
17-
import java.util.Set;
1811
import org.junit.jupiter.api.extension.RegisterExtension;
1912

2013
class RatpackPooledHttpClientTest extends AbstractRatpackPooledHttpClientTest {
2114

2215
@RegisterExtension
2316
static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent();
24-
25-
@Override
26-
protected Set<AttributeKey<?>> computeHttpAttributes(URI uri) {
27-
Set<AttributeKey<?>> attributes = new HashSet<>(super.computeHttpAttributes(uri));
28-
// underlying netty instrumentation does not provide these
29-
attributes.remove(SERVER_ADDRESS);
30-
attributes.remove(SERVER_PORT);
31-
return attributes;
32-
}
3317
}

instrumentation/ratpack/ratpack-1.4/testing/src/main/java/io/opentelemetry/instrumentation/ratpack/client/AbstractRatpackHttpClientTest.java

+65-37
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,20 @@
55

66
package io.opentelemetry.instrumentation.ratpack.client;
77

8+
import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
9+
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
10+
811
import io.netty.channel.ConnectTimeoutException;
912
import io.netty.handler.timeout.ReadTimeoutException;
1013
import io.opentelemetry.api.common.AttributeKey;
1114
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest;
1215
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientResult;
1316
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions;
17+
import io.opentelemetry.semconv.NetworkAttributes;
1418
import java.net.URI;
1519
import java.time.Duration;
1620
import java.util.Collections;
21+
import java.util.HashSet;
1722
import java.util.Map;
1823
import java.util.Set;
1924
import org.junit.jupiter.api.AfterAll;
@@ -29,13 +34,13 @@
2934

3035
public abstract class AbstractRatpackHttpClientTest extends AbstractHttpClientTest<Void> {
3136

32-
private final ExecHarness exec = ExecHarness.harness();
37+
protected final ExecHarness exec = ExecHarness.harness();
3338

34-
private HttpClient client;
35-
private HttpClient singleConnectionClient;
39+
protected HttpClient client;
40+
protected HttpClient singleConnectionClient;
3641

3742
@BeforeAll
38-
void setUpClient() throws Exception {
43+
protected void setUpClient() throws Exception {
3944
exec.run(
4045
unused -> {
4146
client = buildHttpClient();
@@ -66,7 +71,7 @@ public Void buildRequest(String method, URI uri, Map<String, String> headers) {
6671
@Override
6772
public int sendRequest(Void request, String method, URI uri, Map<String, String> headers)
6873
throws Exception {
69-
return exec.yield(unused -> internalSendRequest(client, method, uri, headers))
74+
return exec.yield(execution -> internalSendRequest(client, method, uri, headers))
7075
.getValueOrThrow();
7176
}
7277

@@ -78,13 +83,17 @@ public final void sendRequestWithCallback(
7883
Map<String, String> headers,
7984
HttpClientResult httpClientResult)
8085
throws Exception {
81-
exec.execute(
82-
Operation.of(
83-
() ->
84-
internalSendRequest(client, method, uri, headers)
85-
.result(
86-
result ->
87-
httpClientResult.complete(result::getValue, result.getThrowable()))));
86+
exec.yield(
87+
(e) ->
88+
Operation.of(
89+
() ->
90+
internalSendRequest(client, method, uri, headers)
91+
.result(
92+
result ->
93+
httpClientResult.complete(
94+
result::getValue, result.getThrowable())))
95+
.promise())
96+
.getValueOrThrow();
8897
}
8998

9099
// overridden in RatpackForkedHttpClientTest
@@ -118,32 +127,13 @@ protected void configure(HttpClientTestOptions.Builder optionsBuilder) {
118127
.getValueOrThrow();
119128
});
120129

121-
optionsBuilder.setExpectedClientSpanNameMapper(
122-
(uri, method) -> {
123-
switch (uri.toString()) {
124-
case "http://localhost:61/": // unopened port
125-
case "https://192.0.2.1/": // non routable address
126-
return "CONNECT";
127-
default:
128-
return HttpClientTestOptions.DEFAULT_EXPECTED_CLIENT_SPAN_NAME_MAPPER.apply(
129-
uri, method);
130-
}
131-
});
130+
if (useNettyClientAttributes()) {
131+
optionsBuilder.setExpectedClientSpanNameMapper(
132+
AbstractRatpackHttpClientTest::nettyExpectedClientSpanNameMapper);
133+
}
132134

133135
optionsBuilder.setClientSpanErrorMapper(
134-
(uri, exception) -> {
135-
if (uri.toString().equals("https://192.0.2.1/")) {
136-
return new ConnectTimeoutException(
137-
"connection timed out"
138-
+ (Boolean.getBoolean("testLatestDeps") ? " after 2000 ms" : "")
139-
+ ": /192.0.2.1:443");
140-
} else if (OS.WINDOWS.isCurrentOs() && uri.toString().equals("http://localhost:61/")) {
141-
return new ConnectTimeoutException("connection timed out: localhost/127.0.0.1:61");
142-
} else if (uri.getPath().equals("/read-timeout")) {
143-
return ReadTimeoutException.INSTANCE;
144-
}
145-
return exception;
146-
});
136+
AbstractRatpackHttpClientTest::nettyClientSpanErrorMapper);
147137

148138
optionsBuilder.setHttpAttributes(this::computeHttpAttributes);
149139

@@ -160,7 +150,45 @@ protected Set<AttributeKey<?>> computeHttpAttributes(URI uri) {
160150
case "https://192.0.2.1/": // non routable address
161151
return Collections.emptySet();
162152
default:
163-
return HttpClientTestOptions.DEFAULT_HTTP_ATTRIBUTES;
153+
HashSet<AttributeKey<?>> attributes =
154+
new HashSet<>(HttpClientTestOptions.DEFAULT_HTTP_ATTRIBUTES);
155+
if (useNettyClientAttributes()) {
156+
// underlying netty instrumentation does not provide these
157+
attributes.remove(SERVER_ADDRESS);
158+
attributes.remove(SERVER_PORT);
159+
} else {
160+
// ratpack client instrumentation does not provide this
161+
attributes.remove(NetworkAttributes.NETWORK_PROTOCOL_VERSION);
162+
}
163+
return attributes;
164+
}
165+
}
166+
167+
protected boolean useNettyClientAttributes() {
168+
return true;
169+
}
170+
171+
private static Throwable nettyClientSpanErrorMapper(URI uri, Throwable exception) {
172+
if (uri.toString().equals("https://192.0.2.1/")) {
173+
return new ConnectTimeoutException(
174+
"connection timed out"
175+
+ (Boolean.getBoolean("testLatestDeps") ? " after 2000 ms" : "")
176+
+ ": /192.0.2.1:443");
177+
} else if (OS.WINDOWS.isCurrentOs() && uri.toString().equals("http://localhost:61/")) {
178+
return new ConnectTimeoutException("connection timed out: localhost/127.0.0.1:61");
179+
} else if (uri.getPath().equals("/read-timeout")) {
180+
return ReadTimeoutException.INSTANCE;
181+
}
182+
return exception;
183+
}
184+
185+
private static String nettyExpectedClientSpanNameMapper(URI uri, String method) {
186+
switch (uri.toString()) {
187+
case "http://localhost:61/": // unopened port
188+
case "https://192.0.2.1/": // non routable address
189+
return "CONNECT";
190+
default:
191+
return HttpClientTestOptions.DEFAULT_EXPECTED_CLIENT_SPAN_NAME_MAPPER.apply(uri, method);
164192
}
165193
}
166194
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
plugins {
2+
id("otel.javaagent-instrumentation")
3+
}
4+
5+
muzzle {
6+
pass {
7+
group.set("io.ratpack")
8+
module.set("ratpack-core")
9+
versions.set("[1.7.0,)")
10+
}
11+
fail {
12+
group.set("io.ratpack")
13+
module.set("ratpack-core")
14+
versions.set("[1.0,1.7)")
15+
}
16+
}
17+
18+
dependencies {
19+
library("io.ratpack:ratpack-core:1.7.0")
20+
21+
implementation(project(":instrumentation:netty:netty-4.1:library"))
22+
implementation(project(":instrumentation:ratpack:ratpack-1.7:library"))
23+
24+
testImplementation(project(":instrumentation:ratpack:ratpack-1.4:testing"))
25+
testInstrumentation(project(":instrumentation:ratpack:ratpack-1.4:javaagent"))
26+
}
27+
28+
tasks {
29+
withType<Test>().configureEach {
30+
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean)
31+
jvmArgs("-Dotel.instrumentation.common.experimental.controller-telemetry.enabled=true")
32+
}
33+
}
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.javaagent.instrumentation.ratpack.v1_7;
7+
8+
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
9+
import static net.bytebuddy.matcher.ElementMatchers.named;
10+
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
11+
12+
import com.google.common.collect.ImmutableList;
13+
import io.opentelemetry.instrumentation.ratpack.v1_7.internal.OpenTelemetryExecInitializer;
14+
import io.opentelemetry.instrumentation.ratpack.v1_7.internal.OpenTelemetryExecInterceptor;
15+
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
16+
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
17+
import net.bytebuddy.asm.Advice;
18+
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
19+
import net.bytebuddy.asm.Advice.AssignReturned.ToFields.ToField;
20+
import net.bytebuddy.description.type.TypeDescription;
21+
import net.bytebuddy.matcher.ElementMatcher;
22+
import ratpack.exec.ExecInitializer;
23+
import ratpack.exec.ExecInterceptor;
24+
25+
public class DefaultExecControllerInstrumentation implements TypeInstrumentation {
26+
27+
@Override
28+
public ElementMatcher<TypeDescription> typeMatcher() {
29+
return named("ratpack.exec.internal.DefaultExecController");
30+
}
31+
32+
@Override
33+
public void transform(TypeTransformer transformer) {
34+
transformer.applyAdviceToMethod(
35+
named("setInitializers")
36+
.and(takesArgument(0, named("com.google.common.collect.ImmutableList"))),
37+
DefaultExecControllerInstrumentation.class.getName() + "$SetInitializersAdvice");
38+
39+
transformer.applyAdviceToMethod(
40+
named("setInterceptors")
41+
.and(takesArgument(0, named("com.google.common.collect.ImmutableList"))),
42+
DefaultExecControllerInstrumentation.class.getName() + "$SetInterceptorsAdvice");
43+
44+
transformer.applyAdviceToMethod(
45+
isConstructor(),
46+
DefaultExecControllerInstrumentation.class.getName() + "$ConstructorAdvice");
47+
}
48+
49+
@SuppressWarnings("unused")
50+
public static class SetInitializersAdvice {
51+
@Advice.OnMethodEnter(suppress = Throwable.class)
52+
@Advice.AssignReturned.ToArguments(@ToArgument(0))
53+
public static ImmutableList<? extends ExecInitializer> enter(
54+
@Advice.Argument(0) ImmutableList<? extends ExecInitializer> initializers) {
55+
return ImmutableList.<ExecInitializer>builder()
56+
.addAll(initializers)
57+
.add(OpenTelemetryExecInitializer.INSTANCE)
58+
.build();
59+
}
60+
}
61+
62+
@SuppressWarnings("unused")
63+
public static class SetInterceptorsAdvice {
64+
@Advice.OnMethodEnter(suppress = Throwable.class)
65+
@Advice.AssignReturned.ToArguments(@ToArgument(0))
66+
public static ImmutableList<? extends ExecInterceptor> enter(
67+
@Advice.Argument(0) ImmutableList<? extends ExecInterceptor> interceptors) {
68+
return ImmutableList.<ExecInterceptor>builder()
69+
.addAll(interceptors)
70+
.add(OpenTelemetryExecInterceptor.INSTANCE)
71+
.build();
72+
}
73+
}
74+
75+
@SuppressWarnings("unused")
76+
public static class ConstructorAdvice {
77+
78+
@SuppressWarnings("UnusedVariable")
79+
@Advice.OnMethodExit(suppress = Throwable.class)
80+
@Advice.AssignReturned.ToFields({
81+
@ToField(value = "initializers", index = 0),
82+
@ToField(value = "interceptors", index = 1)
83+
})
84+
public static Object[] exit(
85+
@Advice.FieldValue("initializers") ImmutableList<? extends ExecInitializer> initializers,
86+
@Advice.FieldValue("interceptors") ImmutableList<? extends ExecInterceptor> interceptors) {
87+
return new Object[] {
88+
ImmutableList.of(OpenTelemetryExecInitializer.INSTANCE),
89+
ImmutableList.of(OpenTelemetryExecInterceptor.INSTANCE)
90+
};
91+
}
92+
}
93+
}

0 commit comments

Comments
 (0)