raphw / byte-buddy

Runtime code generation for the Java virtual machine.
https://bytebuddy.net
Apache License 2.0
6.25k stars 805 forks source link

How to use AgentBuilder correctly ? #96

Closed zcfrank1st closed 8 years ago

zcfrank1st commented 8 years ago

I try to use agent builder to write a java agent to log logs, but it does not work and there are no errors outputing, my main agent code is:


public class LogAgent {
    public static void premain(String args, Instrumentation inst) {
        System.out.println("agent start...");
        try {
            new AgentBuilder.Default()
                    .with(new AgentBuilder.Listener() {
                        @Override
                        public void onTransformation(TypeDescription typeDescription, DynamicType dynamicType) {
                            System.out.println("Transformed - " + typeDescription + ", type = " + dynamicType);
                        }
                        @Override
                        public void onIgnored(TypeDescription typeDescription) {
                        }
                        @Override
                        public void onError(String s, Throwable throwable) {
                            System.out.println("error --- " + s);
                            System.out.println("error === " + throwable.getMessage());
                            throwable.printStackTrace();
                        }
                        @Override
                        public void onComplete(String s) {
                            System.out.println("complete --- " + s);
                        }
                    })
                    .type(isAnnotatedWith(Log.class))
                    .transform((builder, typeDescription) -> builder
                            .method(any())            

.intercept(MethodDelegation.to(LogInterceptor.class).andThen(SuperMethodCall.INSTANCE)))
                    .installOn(inst);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

and my demo code is:


public class Main {
    @Log
    void hello () {
        System.out.println("hello");
    }
    public static void main(String[] args) {
        Main main = new Main();
        main.hello();
    }
}

the intercepter is:


public class LogInterceptor {
    public static Logger logger = LoggerFactory.getLogger(LogInterceptor.class);
    static void interceptor(@Origin Method method) {
        System.out.println("=========");
        logger.info(method.getName());
    }
}
how to fix that ? BTW, are there any resources can help me learn bytebuddy deeply ? Thank you ! :laughing:
raphw commented 8 years ago

You specify:

.type(isAnnotatedWith(Log.class))
.transform((builder, typeDescription) -> builder.method(any())
      .intercept(MethodDelegation.to(LogInterceptor.class)
           .andThen(SuperMethodCall.INSTANCE)))       

What you are saying is that you want to intercept any type that is annotated with @Log. However, only your method is annotated with this annotation. Try declaresMethod(isAnnotatedWith(Log.class)) or any().

Also, make sure that this is what you want. Currently, you intercept any method if it is inherited or not. Consider adding isDeclaredBy(typeDescription) to your method matching.

Byte Buddy builds a standard Java agent. The official documentation is rather short but contains all relevant information.

zcfrank1st commented 8 years ago

Thanks, but I tried


.type(declaresMethod(isAnnotatedWith(Log.class)))
.transform((builder, typeDescription) -> builder
                  .method(isDeclaredBy(any()))
                  .intercept(MethodDelegation.to(LogInterceptor.class).andThen(SuperMethodCall.INSTANCE)))

and run java -javaagent:logger-1.0-SNAPSHOT.jar -cp /Users/zcfrank1st/Desktop/git-svn/agent-demo/target/agent-demo-1.0-SNAPSHOT.jar Main the terminal prints None of [] allows for delegation from void Main.hello() java.lang.IllegalArgumentException: None of [] allows for delegation from void Main.hello()

raphw commented 8 years ago

Your

static void interceptor(@Origin Method method)

method is package-private. Is this method visible to the Hello class? If not, change the visibility of the static method to public or change the package of the interceptor class and it should work.

zcfrank1st commented 8 years ago

:+1: it worked ! Thanks a lot ~