Reputation: 1
I looked at ByteBuddy documentation and have also looked at few of the Java Agent implementations that are using ByteBuddy. But I am still not very clear on what is the right way to use the ByteBuddy agent.
This is the code I used to bootstrap my agent:
public class ByteBuddyAgent {
public static void premain(String arguments, Instrumentation instrumentation) {
System.out.println("Bootstrapping ByteBuddy Agent");
new AgentBuilder.Default()
.with(new AgentBuilder.InitializationStrategy.SelfInjection.Eager())
.type(ElementMatchers.hasSuperClass(ElementMatchers.nameContains("Level1")))
.transform(new ByteBuddyTransformer()
.installOn(instrumentation);
}
private static class ByteBuddyTransformer implements AgentBuilder.Transformer{
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module) {
return builder.method(ElementMatchers.named("printLevel"))
.intercept(Advice.to(MethodTracker.class));
}
}
}
This is my Advice class where I have tried different annotations supported by Advice and it worked fine.
public class MethodTracker {
@Advice.OnMethodEnter
public static Object onMethodBegin(@Advice.This Object invokedObject, @Advice.AllArguments Object[] arguments,
@Advice.FieldValue("name") Object fieldValue, @Advice.Origin Object origin,
@Advice.Local("localVariable") Object localVariable) {
System.out.println("=======on Method Begin Running with ByteBuddy=======, " + invokedObject);
System.out.println("======Printing arguments=======");
for(Object obj: arguments){
System.out.println("Argument:: " + obj);
}
localVariable = "Gunika";
System.out.println("FieldValue:: " + fieldValue);
System.out.println("Origin:: " + origin);
return "ReturningStateFromOnMethodBegin";
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void onMethodEnd(@Advice.This Object invokedObject, @Advice.Return Object returnValue,
@Advice.FieldValue("name") Object fieldValue, @Advice.Enter Object state,
@Advice.Local("localVariable") Object localVariable){
System.out.println("=======on Method End Running with ByteBuddy======= " + invokedObject);
System.out.println("Return value is " + returnValue);
System.out.println("FieldValue:: " + fieldValue);
System.out.println("FieldValue:: " + fieldValue);
System.out.println("State:: " + state);
System.out.println("LocalVariable:: " + localVariable);
}
}
The questions that I have are as follows:
Right now in my sample app, I have just tried matching with 1 rule. But if there are “n” rules that I want to apply what is the right away to achieve that.
There are initial set of rules that are applied/provided to the agent. Now let's say at some point of time I want to add another rule. What is the correct way to achieve that?
Does the AgentBuilder instance that we create should be created only once in the Java Agent?
Any other information that should be taken care while using ByteBuddy agent would be helpful.
Upvotes: 0
Views: 2427
Reputation: 44042
Advice.to(MethodTracker.class)
is pretty expensive. If you instrument many classes and want to spend the memory, I'd recommend you to reuse the instance, it is immutable.
Other than that, @Advice.AllArguments
is more expensive than using specialized advice classes that read particular arguments, if you can afford it. This is however rather a JVM question than a Byte Buddy-specific one. You can use -Dnet.bytebuddy.dump=/some/folder
to see what byte code is generated. Expensiveness often lies burried what constructs you go for.
Upvotes: 0