Saturday, October 9, 2010

Solve your Java runtime mysteries easily with Byteman

Update February 2012

Use the following to easily use Byteman on AS7, using the HelloWorld quickstart:

-- Script to attach, check, and submit rule -----
#!/bin/bash
export JBOSS_HOME=/home/rick/Tools/JBoss_Org/jboss-as-7.0.2.Final
echo $JBOSS_HOME
export BYTEMAN_HOME=/home/rick/Tools/MISC_TOOLS/byteman-2.0/byteman-download-2.0.0
export BYTEMAN_BIN=$BYTEMAN_HOME/bin
# Only install once.....
# $BYTEMAN_BIN/bminstall.sh -b -Dorg.jboss.byteman.transform.all $JBOSS_HOME/jboss-modules.jar

export QS_HELLOWORLD_TGT=/home/rick/Tools/JBoss_Org/jboss-as-quickstarts-7.0.2.CR1/helloworld/target/classes
# check it
$BYTEMAN_BIN/bmcheck.sh -cp $QS_HELLOWORLD_TGT RicksScript.btm

# add the rule
$BYTEMAN_BIN/bmsubmit.sh RicksScript.btm

-------The Rule. Check the arbitrary Java code used! --------------

RULE trace main entry
CLASS org.jboss.as.quickstarts.helloworld.HelloService
METHOD createHelloMessage
AT ENTRY
IF true
#DO traceln("entering createHelloMessage")
#DO traceStack("found the caller!\n", 100)
DO System.out.println("Hey, I'm random java code!");
ENDRULE

-------------

Have you heard of Byteman? It's sort of like AOP-lite. With a small script and a lightly doctored startup command, you can have x-ray vision into your Java applications. You don't even have to alter your source code, and it's easy to use.

Here's a quick example. Let's say we have a Java application where some method is called at some point, and you want to know when that method is called and what's being passed to it.

So let's say we have an application that provides this output. (I'll show you the source code in a bit.)
-----------------------------------------------------------------
Suspects about to do stuff!
Thump! A murder happens!
Suspects done moving around!
-----------------------------------------------------------------

Well, we don't know much about who committed the crime, do we? (In fairness, we don't even know who the suspects are yet.) But how about if you had the source code? Then could you tell? I doubt it. Here's the source:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Clue {
private void makeMystery(){
List suspects = new ArrayList();
suspects.add("Colonel Mustard");
suspects.add("Mr. Green");
suspects.add("Miss Scarlet");
Random gen = new Random();
// determine the killer!
int theKiller = gen.nextInt(3);
System.out.println("Suspects about to do stuff!");
for (String suspect : suspects){
walkThroughKitchen(suspect);
// maybe commit the crime!
if (suspect.equals(suspects.get(theKiller))){
commitCrime(suspect);
}
walkThroughLibrary(suspect);
}
System.out.println("Suspects done moving around!");
}

private void walkThroughLibrary(String suspect) {
// walks through...
}

private void commitCrime(String suspect) {
System.out.println("Thump! A murder happens!");
}

private void walkThroughKitchen(String suspect) {
// walks through
}

public static void main(String[] args) {
Clue clue = new Clue();
clue.makeMystery();
}

}

I defy you to tell me who committed the crime! But with Byteman you can tell!

So let's set things up. Aside from downloading Byteman (found here), you need to do a few things.
  1. Make your application into a jar (using jar -cvf someJar.jar *.class, perhaps). This is done as a convenience to make it easier to put on a classpath.
  2. Make a Byteman script, telling it what you want to see.
  3. Make a command-line script to invoke your application.
Step 1 should be familiar to most Java coders.

Step 2. For the above class, let's make a script like this:

 #

# clue_script.txt - A simple script to intercept calls to a method
#
RULE Simple byteman example - watch a method
CLASS Clue
METHOD commitCrime(String)
AT EXIT
BIND THE_MURDERER = $1
IF TRUE
DO traceln("Caught the murderer! It was " + $1)
ENDRULE

Step 3. Add the necessary agent to your startup shell script.
java -javaagent:/home/rick/Tools/Examples/Byteman/byteman-1.3.0/lib/byteman.jar=script:clue_script.txt -classpath clue.jar Clue


Now when we run the script, we see this:
---------------------------------------------------------------
Suspects about to do stuff!
Thump! A murder happens!
Caught the murderer! It was Colonel Mustard
Suspects done moving around!
---------------------------------------------------------------

There we have it! Byteman has let us find out which arguments were being passed to that method, and we did it without altering the source for the application, without attaching a remote debugger, and without much trouble.

Byteman can do much more, though. It can provide stack traces on demand, it can inject faults for testing and other neat tricks. You can add an arbitrary Java helper .jar to help you do things-- just bind it with a "-b" option.  Best of all, it doesn't cost anything. Check it out today, here.

Happy Inspecting!

7 comments:

John Mazz said...

Byteman is a great runtime debug/analysis tool that is easy to set up and start up. This article is very good - short and sweet - illustrating how easy it is to use. (BTW: I like the suspect-murder theme :)

I, myself, love Byteman so much I wrote a blog showing an RHQ plugin I developed that allows Byteman to be managed through the RHQ GUI - you can upload rules to the Byteman agent, remove rules, etc.

Anonymous said...

Byteman does sound interesting. I've done a bit with a related tool named BTrace. One really cool thing about BTrace is that you can use it in a limited way to trace a running app without starting a java agent.

--Matt

Phoenix2life said...

Thanks for sharing information about Byteman using awesome real world story telling mechanism. Cool. Use of murder OO code is perfect. Ofcourse the sample text script for ByteMan is so neat to explain end to end flow and steps to incorporate it into real world scenario.

Also both the comments added here responding to your blog post are supplying good information of two tools. RHQ GUI and BTrace.

Emilian Bold said...

Sounds like a lite version of Btrace.

VisualVM with the Btrace plugin (that lets you edit the script right there) is quite a valuable tool.

And, of course, if it's Java6 you don't need an agent.

Andrew Dinn said...

Byteman is not a 'lite' version of btrace. On the contrary, it can do everything btrace does and more. btrace code is essentially read only as it is provide to allow tracing of applications or JVM operation. Byteman supports injection of trace code too but it also allows you to call code with side effects. You can call any method which is in scope at the injection point and you can update state rather than just read it.

This allows Byteman to 'break' code which is very useful for testing. For example, you can force a method to return early with a synthetic result or to throw a checked exception. This was the primary design goal of Byteman -- comparing it to btrace is rather inappropriate since it is a different tool for a different purpose.

Also, the comment about btrace not using an agent is actually a misnomer. btrace has always used a javaagent just like byteman. You can explicitly install the btrace agent on the command line just like Byteman does. However, btrace also allows you to use the VirtualMachine class in the com.sun.tool.attach package to attach to a running JVM and install the agent dynamically. Byteman does not currently provide this option since it ties you down to the Sun/OpenJDK VM (note that Byteman also works on IBM's JDK).

Enthusiast said...

Well, you can use BTrace to break your app (intentionally or not) as well. Just run it in unsafe mode and knock yourself out :)

enum in java said...

I think best part of it is you doesn't require to alter your code. Byteman looks quite promising for java debugging.