Tips: Byteman usage

Recently I spent hours trying to create 2 new maven artifacts (two jars, one containing compiled classes and another containing source codes) by combining 3 other maven artifacts using maven-assembly-plugin. I can not believe how hard it was.

To make a long story short, version 2.2 would mess wiith the name of the artifacts by either appending the assembly id value in the artifact name of both artifacts or by ignoring the id for both (I needed one with id ignored and one with it appended). So I had to stick with version 2.1 but the include/exclude elements were not working as I thought they should and I wanted to debug the code to see why the string patterns I was using were not matching the dependency artifacts included in my pom.xml.

Somehow I couldn't manage to debug maven code with Eclipse so I turned to Byteman for help. This article is a complete example of steps to perform to get a variable value with Byteman.

 

  • Find out the command line being executed by the java program. In my case I did 'ps axwww' and maven was executing with the following command line:

 

java -classpath /opt/maven/boot/plexus-classworlds-2.2.3.jar -Dclassworlds.conf=/opt/maven/bin/m2.conf -Dmaven.home=/opt/maven org.codehaus.plexus.classworlds.launcher.Launcher clean install
  • Create a rule file anywhere in your system. I created rule.txt in the same path I was running maven. The contents were:

 

RULE **** trace Artifact ****
CLASS AssemblyIncludesArtifactFilter
METHOD include
AFTER WRITE $id
IF true
DO traceln($id);
ENDRULE

So in this example RULE is just a name for your rule. CLASS is the name of the class where you want your rule running. This should be the FQCN is there is more than one class with the same name. METHOD is the name of the method inside which your code will run. If there is only one method with that name you don't need to add its parameters. At this point I have to confess I decompiled some classes of the plugin to see the name of the class, method and variable I needed . AFTER WRITE will tell at which point the code will be executed. In my case after the $id variable was assigned a value. IF true is just a simple clause to make it execute everytime. DO traceln($id) prints the value of the variable in the screen. That's it.

  • Modify your command line to use Byteman. In my case it ended up like this:

 

java -javaagent:/home/mmoyses/M2_REPO/org/jboss/byteman/byteman/1.4.1/byteman-1.4.1.jar=script:rule.txt -classpath /opt/maven/boot/plexus-classworlds-2.2.3.jar -Dclassworlds.conf=/opt/maven/bin/m2.conf -Dmaven.home=/opt/maven org.codehaus.plexus.classworlds.launcher.Launcher clean install

So adding -javaagent:<path to byteman>=script:<path to the rule> is what is needed.

 

You will see in the output the value of the variable being written. Pretty cool.

 

Another example of rule I have used in the past is:

 

RULE trace ClientSocketFactory
CLASS org.jboss.security.ssl.ClientSocketFactory
METHOD <init>
IF true
DO traceStack("Invoking constructor of ClientSocketFactory\n", 20)
ENDRULE

What this one will do is print a stack trace of up to 20 lines when the constructor of ClientSocketFactory is invoked.

This might come in handy when you need to find out who is invoking some method of some class.

 

More detailed information about Byteman usage can be found in the official documentation.