Introduction to Byteman

This tutorial introduces the Byteman framework which is part of the JBoss Ecosystem, showing how it can be used to increase your productivity.

Byteman is addressed into the documentation as a tracing, debugging and testing tool which can be used on any Java application.

You might wonder why do we need to learn another tool for tracing and debugging applications ?

Let me tell you with a simple example why ByteMan can be a needful resource for your applications. Supposing that you are hitting a NPE in your Web application. The first and most obvious fix would be either starting a remote debugging session (which may not be always possible) or add some logs in the critical points. In most cases you will resort to modify your code, dedeploy you app and, once fixed the issue, disable or remove the logs.

Here's what you can do with Byteman: inject a rule into your code -without any change in your code- in which you can directly refer to app/runtime data & types. In other words you can write a simple rule which says:

WHEN YOU ENTER THE Dummy SERVLET
THEN DUMP THE HTTPREQUEST

The rule will inject dynamically the code in your application (in this case into the application server) and execute the rule. Once you don't need it any more, just tell to the JVM that you don't need anymore firing ByteMan rules.

Ok. Now let's get our hands dirty. Download Byteman from the source.

In order to start Byteman you need to provide the path to Byteman libs to the -javaagent option, specifying as well the path to the rule file.
For example on windows you would code (You need to define BYTEMAN_HOME as system environment variable):

java -javaagent:%BYTEMAN_HOME%\lib\byteman.jar=script:samplerule.btm com.sample.ByteManTest                        

On Linux

java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:samplerule.btm com.sample.ByteManTest    

A rule file is built-on the following skeleton:

RULE <rule name>
CLASS <class name>
METHOD <method name>
BIND <bindings>
IF   <condition>
DO   <actions>
ENDRULE

The RULE keyword identifies the rule name (Rule names do not have to be unique but it obviously helps when debugging rule scripts if they clearly identify the rule).
The CLASS can identify a class either with or without the package qualification.
The METHOD name can identify a method with or without an argument list or return type.
The BIND specification ca be used to bind application variable into rule variables which can subsequently be referenced in the rule body.
The IF section can be ovbiously used to check Rule conditions
The DO section is the Rule action which can be a rule expression, return values or throw action

Let's try an HelloWorld example:

package com.sample;

public class SimpleTest  
    {

         public static void main(String[] args)

         {         
                 System.out.println("Entering main");
         
         }

    }

And here's a simple rule, name it example.btm:

 RULE trace main entry

CLASS com.sample.SimpleTest

METHOD main

AT ENTRY
IF true

DO traceln("Byteman detected you are entering main")

ENDRULE

As you might guess, here we are defining a rule named "trace main entry" which is fired on main method of the class com.sample.SimpleTest, as soon as the method is entered. In all conditions (IF true) a trace line is printed on the console.

Here's the Eclipse launch configuration for it.

byteman tutorial byteman tutorial byteman tutorial

By running this example you would just see a dummy message on the Console which prints
Byteman detected you are entering main


Now let's see how you can run a Byteman rule when JBoss As triggers the execution of some classes. At first you need to activate Byteman on the JVM startup options (for example on JBoss AS 7 just add this to standalone.conf.bat)


set "JAVA_OPTS=%JAVA_OPTS% -Dorg.jboss.byteman.transform.all -javaagent:C:\byteman\lib\byteman.jar=script:example.btm,boot:C:\byteman\lib\byteman.jar,listener:true"

Now let's write an example.btm rule file (as stated in the startup options) which will dump on the console the com.sample.ByteServlet's query String:

 RULE trace Servlet

CLASS com.sample.ByteServlet

METHOD doGet

AT ENTRY
BIND request = $request;

IF true

DO traceln ("Query String " + request.getQueryString())

ENDRULE

As you can see, this simple rule does one more step compared with the first rule: it binds the doGet request parameter into the Rule's request variable. In the rule action the request's query string is printed.

Define any com.sample.ByteServlet Servlet and invoke it by passing some parameters (/ByteServlet?param1=boo&param2=foo )
As you can see, as soon as the Servlet is invoked you should see the Query String printed on the Console.

Now, let's write a slightly more complex rule:

 RULE trace Servlet

CLASS com.sample.ByteServlet

METHOD doGet
HELPER com.sample.Utility
AT ENTRY
BIND request = $request;

IF true

DO trace ($request)

ENDRULE

This rule includes an HELPER class which means that all the rules in the script will use this class in the Rule actions.
A rule's helper class is used to resolve built-in calls like the trace() method of the com.sample.Utility class, which merely does some request snooping:

package com.sample;

import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;


public class Utility {
    public void trace(HttpServletRequest request) {
        System.out.println("Called trace!");

        Enumeration e = request.getSession().getAttributeNames();
        while (e.hasMoreElements()) {
            String name = (String) e.nextElement();
            System.out.println(name + ": " + request.getSession().getAttribute(name));
        }

        System.out.println("Protocol: " + request.getProtocol());
        System.out.println("Scheme: " + request.getScheme());

        System.out.println("Server Port: " + request.getServerPort());

        System.out.println("Remote Addr: " + request.getRemoteAddr());
        System.out.println("Remote Host: " + request.getRemoteHost());

        System.out.println("Content Length: " + request.getContentLength());
        System.out.close();
    }
}

In this example, as soon as the doGet of the ByteServlet is invoked, the Uility's trace method is invoked, which receives as parameter the HttpServletRerquest. All this, has been done without one single change into the ByteServlet (!). Cool isn't it ?

Follow us on Twitter