Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor TypeInstrumentation#transformers() method #3019

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions docs/contributing/writing-instrumentation-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,15 +166,24 @@ public ElementMatcher<? super TypeDescription> typeMatcher() {
}
```

### `transformers()`
The last `TypeInstrumentation` method describes which methods should be instrumented with which
advice classes. It is suggested to make the method matchers as strict as possible - the type
instrumentation should only instrument the code that it's supposed to, not more.
### `transform(TypeTransformer)`

The last `TypeInstrumentation` method describes what transformations should be applied to the
matched type. Type `TypeTransformer` interface (implemented internally by the agent) defines a set
of available transformations that you can apply:

* Calling `applyAdviceToMethod(ElementMatcher<? super MethodDescription>, String)` allows you to
apply an advice class (the second parameter) to all matching methods (the first parameter). It is
suggested to make the method matchers as strict as possible - the type instrumentation should
only instrument the code that it's supposed to, not more.
* `applyTransformer(AgentBuilder.Transformer)` allows you to inject an arbitrary ByteBuddy
transformer. This is an advanced, low-level option that will not be subjected to muzzle safety
checks and helper class detection - use it responsibly.

```java
@Override
public Map<?extends ElementMatcher<? super MethodDescription>, String> transformers() {
return Collections.singletonMap(
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
isPublic()
.and(named("someMethod"))
.and(takesArguments(2))
Expand All @@ -188,8 +197,8 @@ For matching built-in Java types you can use the `takesArgument(0, String.class)
originating from the instrumented library need to be matched using the `named()` matcher.

Implementations of `TypeInstrumentation` will often implement advice classes as static inner
classes. These classes are referred to by name in the mappings from method descriptor to advice
class, typically in the `transform()` method.
classes. These classes are referred to by name when applying advice classes to methods in
the `transform()` method.

You probably noticed in the example above that the advice class is being referenced in a slightly
peculiar way:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@
import akka.dispatch.Envelope;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.concurrent.AdviceUtils;
import io.opentelemetry.javaagent.instrumentation.api.concurrent.State;
import java.util.Collections;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

Expand All @@ -30,8 +28,8 @@ public ElementMatcher<TypeDescription> typeMatcher() {
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will not miss this method signature 😂

return Collections.singletonMap(
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
named("invoke").and(takesArgument(0, named("akka.dispatch.Envelope"))),
AkkaActorCellInstrumentation.class.getName() + "$InvokeStateAdvice");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,18 @@

package io.opentelemetry.javaagent.instrumentation.akkaactor;

import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;

import akka.dispatch.Envelope;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.api.concurrent.ExecutorInstrumentationUtils;
import io.opentelemetry.javaagent.instrumentation.api.concurrent.State;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

Expand All @@ -30,8 +28,8 @@ public ElementMatcher<TypeDescription> typeMatcher() {
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
named("dispatch")
.and(takesArgument(0, named("akka.actor.ActorCell")))
.and(takesArgument(1, named("akka.dispatch.Envelope"))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@

import akka.dispatch.forkjoin.ForkJoinTask;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.instrumentation.api.concurrent.ExecutorInstrumentationUtils;
import io.opentelemetry.javaagent.instrumentation.api.concurrent.State;
import java.util.HashMap;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

Expand All @@ -32,21 +30,19 @@ public ElementMatcher<TypeDescription> typeMatcher() {
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
Map<ElementMatcher<? super MethodDescription>, String> transformers = new HashMap<>();
transformers.put(
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
named("execute")
.and(takesArgument(0, named(AkkaForkJoinTaskInstrumentation.TASK_CLASS_NAME))),
AkkaForkJoinPoolInstrumentation.class.getName() + "$SetAkkaForkJoinStateAdvice");
transformers.put(
transformer.applyAdviceToMethod(
named("submit")
.and(takesArgument(0, named(AkkaForkJoinTaskInstrumentation.TASK_CLASS_NAME))),
AkkaForkJoinPoolInstrumentation.class.getName() + "$SetAkkaForkJoinStateAdvice");
transformers.put(
transformer.applyAdviceToMethod(
nameMatches("invoke")
.and(takesArgument(0, named(AkkaForkJoinTaskInstrumentation.TASK_CLASS_NAME))),
AkkaForkJoinPoolInstrumentation.class.getName() + "$SetAkkaForkJoinStateAdvice");
return transformers;
}

public static class SetAkkaForkJoinStateAdvice {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass;
import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
Expand All @@ -17,14 +16,13 @@
import akka.dispatch.forkjoin.ForkJoinTask;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.javaagent.instrumentation.api.ContextStore;
import io.opentelemetry.javaagent.instrumentation.api.InstrumentationContext;
import io.opentelemetry.javaagent.instrumentation.api.concurrent.AdviceUtils;
import io.opentelemetry.javaagent.instrumentation.api.concurrent.State;
import java.util.Map;
import java.util.concurrent.Callable;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

Expand All @@ -48,8 +46,8 @@ public ElementMatcher<TypeDescription> typeMatcher() {
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
named("exec").and(takesArguments(0)).and(not(isAbstract())),
AkkaForkJoinTaskInstrumentation.class.getName() + "$ForkJoinTaskAdvice");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@
import io.opentelemetry.context.propagation.TextMapSetter;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import scala.concurrent.Future;
Expand All @@ -50,19 +48,17 @@ public ElementMatcher<TypeDescription> typeMatcher() {
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
Map<ElementMatcher<? super MethodDescription>, String> transformers = new HashMap<>();
public void transform(TypeTransformer transformer) {
// This is mainly for compatibility with 10.0
transformers.put(
transformer.applyAdviceToMethod(
named("singleRequest")
.and(takesArgument(0, named("akka.http.scaladsl.model.HttpRequest"))),
AkkaHttpClientInstrumentationModule.class.getName() + "$SingleRequestAdvice");
// This is for 10.1+
transformers.put(
transformer.applyAdviceToMethod(
named("singleRequestImpl")
.and(takesArgument(0, named("akka.http.scaladsl.model.HttpRequest"))),
AkkaHttpClientInstrumentationModule.class.getName() + "$SingleRequestAdvice");
return transformers;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import java.util.HashMap;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import scala.Function1;
Expand All @@ -48,21 +46,19 @@ public ElementMatcher<TypeDescription> typeMatcher() {
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
public void transform(TypeTransformer transformer) {
// Instrumenting akka-streams bindAndHandle api was previously attempted.
// This proved difficult as there was no clean way to close the async scope
// in the graph logic after the user's request handler completes.
//
// Instead, we're instrumenting the bindAndHandle function helpers by
// wrapping the scala functions with our own handlers.
Map<ElementMatcher<? super MethodDescription>, String> transformers = new HashMap<>();
transformers.put(
transformer.applyAdviceToMethod(
named("bindAndHandleSync").and(takesArgument(0, named("scala.Function1"))),
AkkaHttpServerInstrumentationModule.class.getName() + "$AkkaHttpSyncAdvice");
transformers.put(
transformer.applyAdviceToMethod(
named("bindAndHandleAsync").and(takesArgument(0, named("scala.Function1"))),
AkkaHttpServerInstrumentationModule.class.getName() + "$AkkaHttpAsyncAdvice");
return transformers;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import java.util.Collections;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.camel.CamelContext;
Expand Down Expand Up @@ -53,8 +51,8 @@ public ElementMatcher<TypeDescription> typeMatcher() {
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return Collections.singletonMap(
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
named("start").and(isPublic()).and(takesArguments(0)),
ApacheCamelInstrumentationModule.class.getName() + "$ContextAdvice");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@
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.TypeTransformer;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

Expand Down Expand Up @@ -49,9 +48,8 @@ public ElementMatcher<TypeDescription> typeMatcher() {
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
public void transform(TypeTransformer transformer) {
// Nothing to transform, this type instrumentation is only used for injecting resources.
return Collections.emptyMap();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed;
import static io.opentelemetry.javaagent.instrumentation.apachehttpasyncclient.ApacheHttpAsyncClientTracer.tracer;
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
Expand All @@ -19,10 +18,9 @@
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import java.io.IOException;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.http.HttpException;
Expand All @@ -49,8 +47,8 @@ public ElementMatcher<TypeDescription> typeMatcher() {
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
isMethod()
.and(named("execute"))
.and(takesArguments(4))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import static io.opentelemetry.javaagent.instrumentation.apachehttpclient.v2_0.ApacheHttpClientInstrumenters.instrumenter;
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
Expand All @@ -21,10 +20,9 @@
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.commons.httpclient.HttpMethod;
Expand Down Expand Up @@ -53,8 +51,8 @@ public ElementMatcher<TypeDescription> typeMatcher() {
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
public void transform(TypeTransformer transformer) {
transformer.applyAdviceToMethod(
isMethod()
.and(named("executeMethod"))
.and(takesArguments(3))
Expand Down
Loading