-
Notifications
You must be signed in to change notification settings - Fork 866
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add agent instrumentation for Ratpack 1.7
- Loading branch information
1 parent
2b5c4f5
commit 9e0c64a
Showing
21 changed files
with
724 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
instrumentation/ratpack/ratpack-1.7/javaagent/build.gradle.kts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
plugins { | ||
id("otel.javaagent-instrumentation") | ||
} | ||
|
||
muzzle { | ||
pass { | ||
group.set("io.ratpack") | ||
module.set("ratpack-core") | ||
versions.set("[1.7.0,)") | ||
} | ||
} | ||
|
||
dependencies { | ||
library("io.ratpack:ratpack-core:1.7.0") | ||
|
||
implementation(project(":instrumentation:netty:netty-4.1:library")) | ||
implementation(project(":instrumentation:ratpack:ratpack-1.4:javaagent")) | ||
implementation(project(":instrumentation:ratpack:ratpack-1.7:library")) | ||
|
||
testImplementation(project(":instrumentation:ratpack:ratpack-1.4:testing")) | ||
|
||
testLibrary("io.ratpack:ratpack-test:1.7.0") | ||
|
||
if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_11)) { | ||
testImplementation("com.sun.activation:jakarta.activation:1.2.2") | ||
} | ||
} | ||
|
||
// to allow all tests to pass we need to choose a specific netty version | ||
if (!(findProperty("testLatestDeps") as Boolean)) { | ||
configurations.configureEach { | ||
if (!name.contains("muzzle")) { | ||
resolutionStrategy { | ||
eachDependency { | ||
// specifying a fixed version for all libraries with io.netty group | ||
if (requested.group == "io.netty" && requested.name != "netty-tcnative") { | ||
useVersion("4.1.37.Final") | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
tasks { | ||
withType<Test>().configureEach { | ||
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean) | ||
} | ||
} | ||
|
||
tasks.withType<Test>().configureEach { | ||
jvmArgs("-Dotel.instrumentation.common.experimental.controller-telemetry.enabled=true") | ||
} |
55 changes: 55 additions & 0 deletions
55
.../main/java/io/opentelemetry/javaagent/instrumentation/ratpack/v1_7/DownstreamWrapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.ratpack.v1_7; | ||
|
||
import io.opentelemetry.context.Context; | ||
import io.opentelemetry.context.Scope; | ||
import ratpack.exec.Downstream; | ||
|
||
public class DownstreamWrapper<T> implements Downstream<T> { | ||
|
||
private final Downstream<T> delegate; | ||
private final Context parentContext; | ||
|
||
private DownstreamWrapper(Downstream<T> delegate, Context parentContext) { | ||
assert parentContext != null; | ||
this.delegate = delegate; | ||
this.parentContext = parentContext; | ||
} | ||
|
||
@Override | ||
public void success(T value) { | ||
try (Scope ignored = parentContext.makeCurrent()) { | ||
delegate.success(value); | ||
} | ||
} | ||
|
||
@Override | ||
public void error(Throwable throwable) { | ||
try (Scope ignored = parentContext.makeCurrent()) { | ||
delegate.error(throwable); | ||
} | ||
} | ||
|
||
@Override | ||
public void complete() { | ||
try (Scope ignored = parentContext.makeCurrent()) { | ||
delegate.complete(); | ||
} | ||
} | ||
|
||
public static <T> Downstream<T> wrapIfNeeded(Downstream<T> delegate) { | ||
if (delegate instanceof DownstreamWrapper) { | ||
return delegate; | ||
} | ||
Context context = Context.current(); | ||
if (context == Context.root()) { | ||
// Skip wrapping, there is no need to propagate root context. | ||
return delegate; | ||
} | ||
return new DownstreamWrapper<>(delegate, context); | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
...va/io/opentelemetry/javaagent/instrumentation/ratpack/v1_7/HttpClientInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.ratpack.v1_7; | ||
|
||
import static net.bytebuddy.matcher.ElementMatchers.isMethod; | ||
import static net.bytebuddy.matcher.ElementMatchers.isStatic; | ||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; | ||
|
||
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 ratpack.http.client.HttpClient; | ||
|
||
public class HttpClientInstrumentation implements TypeInstrumentation { | ||
|
||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return named("ratpack.http.client.HttpClient"); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
transformer.applyAdviceToMethod( | ||
isMethod() | ||
.and(isStatic()) | ||
.and(named("of")) | ||
.and(takesArgument(0, named("ratpack.func.Action"))), | ||
HttpClientInstrumentation.class.getName() + "$OfAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class OfAdvice { | ||
|
||
@Advice.OnMethodExit(suppress = Throwable.class) | ||
public static void injectTracing(@Advice.Return(readOnly = false) HttpClient httpClient) | ||
throws Exception { | ||
httpClient = RatpackSingletons.telemetry().instrumentHttpClient(httpClient); | ||
} | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
...io/opentelemetry/javaagent/instrumentation/ratpack/v1_7/RatpackInstrumentationModule.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.ratpack.v1_7; | ||
|
||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; | ||
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 io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; | ||
import java.util.List; | ||
import net.bytebuddy.matcher.ElementMatcher; | ||
|
||
@AutoService(InstrumentationModule.class) | ||
public class RatpackInstrumentationModule extends InstrumentationModule | ||
implements ExperimentalInstrumentationModule { | ||
public RatpackInstrumentationModule() { | ||
super("ratpack", "ratpack-1.7"); | ||
} | ||
|
||
@Override | ||
public String getModuleGroup() { | ||
// relies on netty | ||
return "netty"; | ||
} | ||
|
||
@Override | ||
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() { | ||
// Only activate when running ratpack 1.7 or later | ||
return hasClassesNamed("ratpack.exec.util.retry.Delay"); | ||
} | ||
|
||
@Override | ||
public List<TypeInstrumentation> typeInstrumentations() { | ||
return asList( | ||
new ServerRegistryInstrumentation(), | ||
new HttpClientInstrumentation(), | ||
new RequestActionSupportInstrumentation()); | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
.../main/java/io/opentelemetry/javaagent/instrumentation/ratpack/v1_7/RatpackSingletons.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.ratpack.v1_7; | ||
|
||
import io.netty.channel.Channel; | ||
import io.opentelemetry.api.GlobalOpenTelemetry; | ||
import io.opentelemetry.context.Context; | ||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; | ||
import io.opentelemetry.instrumentation.netty.v4_1.internal.AttributeKeys; | ||
import io.opentelemetry.instrumentation.ratpack.v1_7.RatpackTelemetry; | ||
import io.opentelemetry.instrumentation.ratpack.v1_7.internal.ContextHolder; | ||
import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig; | ||
import io.opentelemetry.javaagent.bootstrap.internal.ExperimentalConfig; | ||
import ratpack.exec.Execution; | ||
|
||
public final class RatpackSingletons { | ||
|
||
static { | ||
TELEMETRY = | ||
RatpackTelemetry.builder(GlobalOpenTelemetry.get()) | ||
.configure(AgentCommonConfig.get()) | ||
.build(); | ||
} | ||
|
||
private static final Instrumenter<String, Void> INSTRUMENTER = | ||
Instrumenter.<String, Void>builder( | ||
GlobalOpenTelemetry.get(), "io.opentelemetry.ratpack-1.7", s -> s) | ||
.setEnabled(ExperimentalConfig.get().controllerTelemetryEnabled()) | ||
.buildInstrumenter(); | ||
|
||
public static Instrumenter<String, Void> instrumenter() { | ||
return INSTRUMENTER; | ||
} | ||
|
||
private static final RatpackTelemetry TELEMETRY; | ||
|
||
public static RatpackTelemetry telemetry() { | ||
return TELEMETRY; | ||
} | ||
|
||
public static void propagateContextToChannel(Execution execution, Channel channel) { | ||
Context parentContext = | ||
execution | ||
.maybeGet(ContextHolder.class) | ||
.map(ContextHolder::context) | ||
.orElse(Context.current()); | ||
channel.attr(AttributeKeys.CLIENT_PARENT_CONTEXT).set(parentContext); | ||
} | ||
|
||
private RatpackSingletons() {} | ||
} |
84 changes: 84 additions & 0 deletions
84
...telemetry/javaagent/instrumentation/ratpack/v1_7/RequestActionSupportInstrumentation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.javaagent.instrumentation.ratpack.v1_7; | ||
|
||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; | ||
import static net.bytebuddy.matcher.ElementMatchers.isMethod; | ||
import static net.bytebuddy.matcher.ElementMatchers.isPrivate; | ||
import static net.bytebuddy.matcher.ElementMatchers.named; | ||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument; | ||
|
||
import io.netty.channel.Channel; | ||
import io.opentelemetry.context.Context; | ||
import io.opentelemetry.context.Scope; | ||
import io.opentelemetry.instrumentation.ratpack.v1_7.internal.ContextHolder; | ||
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 ratpack.exec.Downstream; | ||
import ratpack.exec.Execution; | ||
|
||
public class RequestActionSupportInstrumentation implements TypeInstrumentation { | ||
|
||
@Override | ||
public ElementMatcher<TypeDescription> typeMatcher() { | ||
return extendsClass(named("ratpack.http.client.internal.RequestActionSupport")); | ||
} | ||
|
||
@Override | ||
public void transform(TypeTransformer transformer) { | ||
transformer.applyAdviceToMethod( | ||
isMethod() | ||
.and(isPrivate()) | ||
.and(named("send")) | ||
.and(takesArgument(0, named("ratpack.exec.Downstream"))) | ||
.and(takesArgument(1, named("io.netty.channel.Channel"))), | ||
RequestActionSupportInstrumentation.class.getName() + "$SendAdvice"); | ||
transformer.applyAdviceToMethod( | ||
isMethod().and(named("connect")).and(takesArgument(0, named("ratpack.exec.Downstream"))), | ||
RequestActionSupportInstrumentation.class.getName() + "$ConnectAdvice"); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
public static class SendAdvice { | ||
|
||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static void injectChannelAttribute( | ||
@Advice.FieldValue("execution") Execution execution, | ||
@Advice.Argument(value = 0, readOnly = false) Downstream<?> downstream, | ||
@Advice.Argument(value = 1, readOnly = false) Channel channel) { | ||
RatpackSingletons.propagateContextToChannel(execution, channel); | ||
} | ||
} | ||
|
||
public static class ConnectAdvice { | ||
|
||
@Advice.OnMethodEnter(suppress = Throwable.class) | ||
public static Scope injectChannelAttribute( | ||
@Advice.FieldValue("execution") Execution execution, | ||
@Advice.Argument(value = 0, readOnly = false) Downstream<?> downstream) { | ||
// Propagate the current context to downstream | ||
// since that the is the subsequent | ||
downstream = DownstreamWrapper.wrapIfNeeded(downstream); | ||
|
||
// Capture the CLIENT span and make it current before cally Netty layer | ||
return execution | ||
.maybeGet(ContextHolder.class) | ||
.map(ContextHolder::context) | ||
.map(Context::makeCurrent) | ||
.orElse(null); | ||
} | ||
|
||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) | ||
public static void exit(@Advice.Enter Scope scope) { | ||
if (scope != null) { | ||
scope.close(); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.