Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,13 @@

package io.opentelemetry.javaagent.instrumentation.ratpack;

import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.instrumentation.ratpack.client.AbstractRatpackForkedHttpClientTest;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension;
import java.net.URI;
import java.util.HashSet;
import java.util.Set;
import org.junit.jupiter.api.extension.RegisterExtension;

class RatpackForkedHttpClientTest extends AbstractRatpackForkedHttpClientTest {

@RegisterExtension
static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent();

@Override
protected Set<AttributeKey<?>> computeHttpAttributes(URI uri) {
Set<AttributeKey<?>> attributes = new HashSet<>(super.computeHttpAttributes(uri));
// underlying netty instrumentation does not provide these
attributes.remove(SERVER_ADDRESS);
attributes.remove(SERVER_PORT);
return attributes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,13 @@

package io.opentelemetry.javaagent.instrumentation.ratpack;

import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.instrumentation.ratpack.client.AbstractRatpackHttpClientTest;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension;
import java.net.URI;
import java.util.HashSet;
import java.util.Set;
import org.junit.jupiter.api.extension.RegisterExtension;

class RatpackHttpClientTest extends AbstractRatpackHttpClientTest {

@RegisterExtension
static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent();

@Override
protected Set<AttributeKey<?>> computeHttpAttributes(URI uri) {
Set<AttributeKey<?>> attributes = new HashSet<>(super.computeHttpAttributes(uri));
// underlying netty instrumentation does not provide these
attributes.remove(SERVER_ADDRESS);
attributes.remove(SERVER_PORT);
return attributes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,13 @@

package io.opentelemetry.javaagent.instrumentation.ratpack;

import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.instrumentation.ratpack.client.AbstractRatpackPooledHttpClientTest;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension;
import java.net.URI;
import java.util.HashSet;
import java.util.Set;
import org.junit.jupiter.api.extension.RegisterExtension;

class RatpackPooledHttpClientTest extends AbstractRatpackPooledHttpClientTest {

@RegisterExtension
static final InstrumentationExtension testing = HttpClientInstrumentationExtension.forAgent();

@Override
protected Set<AttributeKey<?>> computeHttpAttributes(URI uri) {
Set<AttributeKey<?>> attributes = new HashSet<>(super.computeHttpAttributes(uri));
// underlying netty instrumentation does not provide these
attributes.remove(SERVER_ADDRESS);
attributes.remove(SERVER_PORT);
return attributes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@

package io.opentelemetry.instrumentation.ratpack.client;

import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;

import io.netty.channel.ConnectTimeoutException;
import io.netty.handler.timeout.ReadTimeoutException;
import io.opentelemetry.api.common.AttributeKey;
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 io.opentelemetry.semconv.NetworkAttributes;
import java.net.URI;
import java.time.Duration;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.AfterAll;
Expand All @@ -29,13 +34,13 @@

public abstract class AbstractRatpackHttpClientTest extends AbstractHttpClientTest<Void> {

private final ExecHarness exec = ExecHarness.harness();
protected final ExecHarness exec = ExecHarness.harness();

private HttpClient client;
private HttpClient singleConnectionClient;
protected HttpClient client;
protected HttpClient singleConnectionClient;

@BeforeAll
void setUpClient() throws Exception {
protected void setUpClient() throws Exception {
exec.run(
unused -> {
client = buildHttpClient();
Expand Down Expand Up @@ -66,7 +71,7 @@ public Void buildRequest(String method, URI uri, Map<String, String> headers) {
@Override
public int sendRequest(Void request, String method, URI uri, Map<String, String> headers)
throws Exception {
return exec.yield(unused -> internalSendRequest(client, method, uri, headers))
return exec.yield(execution -> internalSendRequest(client, method, uri, headers))
.getValueOrThrow();
}

Expand All @@ -78,13 +83,17 @@ public final void sendRequestWithCallback(
Map<String, String> headers,
HttpClientResult httpClientResult)
throws Exception {
exec.execute(
Operation.of(
() ->
internalSendRequest(client, method, uri, headers)
.result(
result ->
httpClientResult.complete(result::getValue, result.getThrowable()))));
exec.yield(
(e) ->
Operation.of(
() ->
internalSendRequest(client, method, uri, headers)
.result(
result ->
httpClientResult.complete(
result::getValue, result.getThrowable())))
.promise())
.getValueOrThrow();
}

// overridden in RatpackForkedHttpClientTest
Expand Down Expand Up @@ -118,32 +127,13 @@ protected void configure(HttpClientTestOptions.Builder optionsBuilder) {
.getValueOrThrow();
});

optionsBuilder.setExpectedClientSpanNameMapper(
(uri, method) -> {
switch (uri.toString()) {
case "http://localhost:61/": // unopened port
case "https://192.0.2.1/": // non routable address
return "CONNECT";
default:
return HttpClientTestOptions.DEFAULT_EXPECTED_CLIENT_SPAN_NAME_MAPPER.apply(
uri, method);
}
});
if (useNettyClientAttributes()) {
optionsBuilder.setExpectedClientSpanNameMapper(
AbstractRatpackHttpClientTest::nettyExpectedClientSpanNameMapper);
}

optionsBuilder.setClientSpanErrorMapper(
(uri, exception) -> {
if (uri.toString().equals("https://192.0.2.1/")) {
return new ConnectTimeoutException(
"connection timed out"
+ (Boolean.getBoolean("testLatestDeps") ? " after 2000 ms" : "")
+ ": /192.0.2.1:443");
} else if (OS.WINDOWS.isCurrentOs() && uri.toString().equals("http://localhost:61/")) {
return new ConnectTimeoutException("connection timed out: localhost/127.0.0.1:61");
} else if (uri.getPath().equals("/read-timeout")) {
return ReadTimeoutException.INSTANCE;
}
return exception;
});
AbstractRatpackHttpClientTest::nettyClientSpanErrorMapper);

optionsBuilder.setHttpAttributes(this::computeHttpAttributes);

Expand All @@ -160,7 +150,45 @@ protected Set<AttributeKey<?>> computeHttpAttributes(URI uri) {
case "https://192.0.2.1/": // non routable address
return Collections.emptySet();
default:
return HttpClientTestOptions.DEFAULT_HTTP_ATTRIBUTES;
HashSet<AttributeKey<?>> attributes =
new HashSet<>(HttpClientTestOptions.DEFAULT_HTTP_ATTRIBUTES);
if (useNettyClientAttributes()) {
// underlying netty instrumentation does not provide these
attributes.remove(SERVER_ADDRESS);
attributes.remove(SERVER_PORT);
} else {
// ratpack client instrumentation does not provide this
attributes.remove(NetworkAttributes.NETWORK_PROTOCOL_VERSION);
}
return attributes;
}
}

protected boolean useNettyClientAttributes() {
return true;
}

private static Throwable nettyClientSpanErrorMapper(URI uri, Throwable exception) {
if (uri.toString().equals("https://192.0.2.1/")) {
return new ConnectTimeoutException(
"connection timed out"
+ (Boolean.getBoolean("testLatestDeps") ? " after 2000 ms" : "")
+ ": /192.0.2.1:443");
} else if (OS.WINDOWS.isCurrentOs() && uri.toString().equals("http://localhost:61/")) {
return new ConnectTimeoutException("connection timed out: localhost/127.0.0.1:61");
} else if (uri.getPath().equals("/read-timeout")) {
return ReadTimeoutException.INSTANCE;
}
return exception;
}

private static String nettyExpectedClientSpanNameMapper(URI uri, String method) {
switch (uri.toString()) {
case "http://localhost:61/": // unopened port
case "https://192.0.2.1/": // non routable address
return "CONNECT";
default:
return HttpClientTestOptions.DEFAULT_EXPECTED_CLIENT_SPAN_NAME_MAPPER.apply(uri, method);
}
}
}
33 changes: 33 additions & 0 deletions instrumentation/ratpack/ratpack-1.7/javaagent/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
plugins {
id("otel.javaagent-instrumentation")
}

muzzle {
pass {
group.set("io.ratpack")
module.set("ratpack-core")
versions.set("[1.7.0,)")
}
fail {
group.set("io.ratpack")
module.set("ratpack-core")
versions.set("[1.0,1.7)")
}
}

dependencies {
library("io.ratpack:ratpack-core:1.7.0")

implementation(project(":instrumentation:netty:netty-4.1:library"))
implementation(project(":instrumentation:ratpack:ratpack-1.7:library"))

testImplementation(project(":instrumentation:ratpack:ratpack-1.4:testing"))
testInstrumentation(project(":instrumentation:ratpack:ratpack-1.4:javaagent"))
}

tasks {
withType<Test>().configureEach {
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean)
jvmArgs("-Dotel.instrumentation.common.experimental.controller-telemetry.enabled=true")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.ratpack.v1_7;

import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;

import com.google.common.collect.ImmutableList;
import io.opentelemetry.instrumentation.ratpack.v1_7.internal.OpenTelemetryExecInitializer;
import io.opentelemetry.instrumentation.ratpack.v1_7.internal.OpenTelemetryExecInterceptor;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
import net.bytebuddy.asm.Advice.AssignReturned.ToFields.ToField;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import ratpack.exec.ExecInitializer;
import ratpack.exec.ExecInterceptor;

public class DefaultExecControllerInstrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("ratpack.exec.internal.DefaultExecController");
}

@Override
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
named("setInitializers")
.and(takesArgument(0, named("com.google.common.collect.ImmutableList"))),
DefaultExecControllerInstrumentation.class.getName() + "$SetInitializersAdvice");

transformer.applyAdviceToMethod(
named("setInterceptors")
.and(takesArgument(0, named("com.google.common.collect.ImmutableList"))),
DefaultExecControllerInstrumentation.class.getName() + "$SetInterceptorsAdvice");

transformer.applyAdviceToMethod(
isConstructor(),
DefaultExecControllerInstrumentation.class.getName() + "$ConstructorAdvice");
}

@SuppressWarnings("unused")
public static class SetInitializersAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
@Advice.AssignReturned.ToArguments(@ToArgument(0))
public static ImmutableList<? extends ExecInitializer> enter(
@Advice.Argument(0) ImmutableList<? extends ExecInitializer> initializers) {
return ImmutableList.<ExecInitializer>builder()
.addAll(initializers)
.add(OpenTelemetryExecInitializer.INSTANCE)
.build();
}
}

@SuppressWarnings("unused")
public static class SetInterceptorsAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
@Advice.AssignReturned.ToArguments(@ToArgument(0))
public static ImmutableList<? extends ExecInterceptor> enter(
@Advice.Argument(0) ImmutableList<? extends ExecInterceptor> interceptors) {
return ImmutableList.<ExecInterceptor>builder()
.addAll(interceptors)
.add(OpenTelemetryExecInterceptor.INSTANCE)
.build();
}
}

@SuppressWarnings("unused")
public static class ConstructorAdvice {

@SuppressWarnings("UnusedVariable")
@Advice.OnMethodExit(suppress = Throwable.class)
@Advice.AssignReturned.ToFields({
@ToField(value = "initializers", index = 0),
@ToField(value = "interceptors", index = 1)
})
public static Object[] exit(
@Advice.FieldValue("initializers") ImmutableList<? extends ExecInitializer> initializers,
@Advice.FieldValue("interceptors") ImmutableList<? extends ExecInterceptor> interceptors) {
return new Object[] {
ImmutableList.of(OpenTelemetryExecInitializer.INSTANCE),
ImmutableList.of(OpenTelemetryExecInterceptor.INSTANCE)
};
}
}
}
Loading
Loading