Version 28

    We're Just Getting Started Here . . .

     

    This article is a simple tutorial  showing you how to get started with Byteman. It explains how to install Byteman and use it to inject side-effects into a simple Java program. The tutorial concentrates on driving Byteman from the command line (which is why you need to download the zip release). A second tutorial explains how you can use Byteman to perform fault injection testing in your unit and integration tests. It describes how to drive Byteman from ant and maven (n.b. maven integration avoids the need to download a Byteman release). It is advised that you work through this tutorial before attempting part 2 as it builds on understanding you will acquire from this tutorial

     

    If you want full information on how to use Byteman the Byteman Programmer's Guide provides an overview of Byteman plus a detailed description of how Byteman operates and how to define rules specifying the side effects you want to inject. It also includes a comprehensive description of how to install Byteman and the various ways you can run Byteman.

     

     

    The tutorial is structured as a FAQ comprising answers to the following questions. If you are new to Byteman you should read it through from start to finish trying out the examples.  If you have used Byteman before and want to refresh your memory or answer a specific question, you can  just jump ahead using one of these links. However, in the latter case you might find it helpful to skim the preceding section(s) in order to fully grasp of what is being presented.

     

     

    Why Would I Use Byteman?

     

    You  use Byteman to change how a Java program operates without having to edit the source code and recompile it. Actually, you can even use Byteman to modify a running application without needing to stop and restart it. Byteman will happily redefine the behaviour of both application classes and JVM runtime classes like String,Thread etc.

     

    The simplest use of Byteman is to insert print statements into code so you can see what your program is doing. Byteman can read and print public, private and protected fields or  local variables. It can even call application methods to compute values to be displayed. Byteman makes very specific, highly localized changes and incurs little overhead in doing so. This is extremely useful when debugging timing dependent code, especially multi-threaded applications where interesting events may happen in several  threads at the same time. It also allows you to debug or monitor a deployed application where it is not acceptable to stop the program using a debugger.

     

    Byteman can also change program control flow. You can inject a call to application or JVM methods which modify application or runtime state. You can also reassign static and instance fields, method parameters and local variables, force a return or throw an exception. This capability is normally used during testing to simulate error situations. Instead of cluttering your application with instrumentation code or using dummy classes to implement faulty behaviour you simply inject code into the application at the precise point where you want it to misbehave.

     

    Note that Byteman requires you to run your application on a Java 6 or higher JVM. You don't need to worry if your code was compiled using an earlier Java release it will still work. However, Byteman emloys JVM functions which are only fully supported on JDK6. If you really need to run on a Java 5 JVM you can download the legacy 1.0.3 Byteman release. It provides all the basic functionality described here but does not support dynamic loading of the Byteman agent and Byteman rules (see the 1.0.3 User Guide for more details).

     

    How Do I Download and Install Byteman?

     

    Before running Byteman you will need to install a Java 6 or higher JVM. In order to execute the programs in this tutorial you will need to compile the source code so you need to install the full JDK which includes the javac compiler and also the Java tools jar. However, it is possible to use Byteman on a system where you only have the JRE installed.  The only feature which requires installation of the full JDK  is dynamic loading of the Byteman agent. Of course, if you are developing Java software you will already have installed the JDK anyway.

     

    The latest Byteman binary release is available from the Byteman project downloads page. Download the binary zip release and unzip it into a directory on your local machine. Now set environment variable BYTEMAN_HOME to refer to this directory. On Linux you execute a command like this

     

    export BYTEMAN_HOME=${HOME}/Downloads/byteman-1.6.0

     

    or on Windows

     

    set BYTEMAN_HOME=C:\Downloads\byteman-1.6.0

     

    The directory identified by BYTEMAN_HOME should include a file called README and subdirectories sample, lib, docs, contrib and bin.

     

    If you are installing Byteman on Linux  then you should add the bin directory to your path so you can use the shell scripts which simplify use of Byteman

     

    export PATH=${PATH}:${BYTEMAN_HOME}/bin

     

    If you are installing Byteman on Windows then you will need to use the java command in place of the shell scripts (note that from release 2.0.1 onwards the  bin directory contains equivalent Windows scripts -- provided as .bat files -- which employ the same command line syntax as the Linux scripts).

     

    Anyway, that's it, installation complete.

     

    How Do I Run A Program Using Byteman?

     

    There are a few different ways to run your Java program with Byteman.The most basic way  is on the java command line using the -javaagent option

     

    Here's a simple application class which will be used to show Byteman in action

     

    package org.my;

    class AppMain

    {

         public static void main(String[] args)

         {

             for (int i = 0; i < args.length; i++) {

                 System.out.println(args[i]);

             }

         }

    }

     

    You would normally compile and run this program as follows:

     

    > javac org/my/AppMain.java

    > java org.my.AppMain foo bar baz

    foo

    bar

    baz

    >

     

    Let's inject to inject some code to trace entry into and exit from method main.

     

    First, we will create a Byteman rule script file. Just open a file in the working directory called appmain.btm and insert the following text

     

    RULE trace main entry

    CLASS AppMain

    METHOD main

    AT ENTRY
    IF true

    DO traceln("entering main")

    ENDRULE

     

    RULE trace main exit

    CLASS AppMain

    METHOD main

    AT EXIT

    IF true

    DO traceln("exiting main")

    ENDRULE

     

    This script contains two rules both of which specify code to be injected into METHOD main of CLASS AppMain. The first rule is injected AT ENTRY i.e. at the start  of the method. The code to be  injected is the IF DO part. In the first rule it calls builtin operation traceln(String) which prints its argument to System.out() followed by a newline The second rule is injected AT EXIT i.e. at the point(s) where control returns from method main. Both rules specify condition IF true which means the DO part is always executed. You can supply a different Java expression if you want to compute whether or not the actions following DO are run.

     

    The -javaagent option used to run the progarm with these Byteman rules is supported by all the main desktop and server JVMs. The syntax is

     

    -javaagent : path_to_agent_jar = agent_option1 , agent_option_2 , . . .

     

    The Linux command to run the program with Byteman and this rule set is

     

    > java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:appmain.btm org.my.AppMain foo bar baz

     

    or on Windows

     

    > java -javaagent:%BYTEMAN_HOME%\lib\byteman.jar=script:appmain.btm org.my.AppMain foo bar baz

     

    The value after the : tells the JVM where to find the Byteman agent jar, ${BYTEMAN_HOME}/lib/byteman.jar. We only supply one agent option following the = sign, script:appmain.btm, specifying the location of the Byteman rule script. The Byteman agent reads this option then loads and injects the rules from file appmain.btm. If we wanted to load more than one script we could provide multiple script:file agent options, separated by a comma.

     

    When you pass -javaagent on the command line the Byteman agent starts executing during JVM startup before the application is run. So, it will read the rules and inject  side effects into  AppMain.main() before this method gets called. The output should be as follows

     

    > java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:appmain.btm org.my.AppMain foo bar baz

    entering main

    foo

    bar

    baz

    exiting main

    >

     

    How Do I Inject Code Into JVM Classes?

     

    Well, let's just try tracing some JVM operations. Insert the following rule text into a new script file called thread.btm.

     

    RULE trace thread start

    CLASS java.lang.Thread

    METHOD start()

    IF true

    DO traceln("*** start for thread: "+ $0.getName())

    ENDRULE

     

    This rule is injected into METHOD start() of the JVM runtime CLASS java.lang.Thread. It prints a trace message pasted together using the String + operator. Now start() is an  instance method so when it is called there is a specific Thread instance which is the target for the method call. The special variable $0 can be used to refer to this target object. start() has no arguments but in other cases where there are the arguments to the call which triggers the rule they can be referenced using $1, $2 etc.


    Byteman knows that $0 references a Thread object so it type checks the method invocation $0.getName() and verifies that the result type is String. The injected code makes a call this method, appends the result to the constant String and passes the result to method traceln() to be written to System.out.

     

    We will inject this rule into a variant of our original class, AppMain2, which creates some threads to do the printing:

     

    package org.my;

     

    class AppMain2

    {

        public static void main(String[] args)

        {

            for (int i = 0; i < args.length; i++) {

                final String arg = args[i];

                Thread thread = new Thread(arg) {

                    public void run() {

                    System.out.println(arg);

                    }

                };

                thread.start();

                try {

                    thread.join();

                } catch (Exception e) {

                }

            }

        }

    }

     

    To run this program using the new script we modify the script: agent option to reference file thread.btm. But that's not enough if we want to inject code into JVM classes. We need to provide some extra options/arguments. On Linux

     

    > java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:thread.btm,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain2 foo bar baz

     

    or on Windows

     

    > java -javaagent:%BYTEMAN_HOME%\lib\byteman.jar=script:thread.btm,boot:%BYTEMAN_HOME%\lib\byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain2 foo bar baz

     

    Class Thread is a JVM class which means it gets loaded by the bootstrap classloader.  Byteman can only inject code into this class if the Byteman agent classes are also loaded by the bootstrap classloader. The extra agent option boot:${BYTEMAN_HOME}/lib/byteman.jar is appended after the script option (note the comma used as a separator). This makes sure that the byteman agent jar is installed into the bootstrap classpath.

     

    Class Thread also happens to be in package java.lang. Normally Byteman is super-cautious and will not inject code into this package in case it beaks the JVM. If you really want to change methods of classes in this package you need to define the system property org.jboss.byteman.transform.all.

     

    When we run the program now we get this output

     

    > java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:thread.btm,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain2 foo bar baz

    *** start for thread: foo

    foo

    *** start for thread: bar

    bar

    *** start for thread: baz

    baz

    >

     

    Is There a Simpler Way To Run Byteman?

     

    On Linux you can use the command script bmjava.sh to wrap up the -javaagent options for you. It looks very much like the java command but it accepts Byteman rule scripts on the command line and bundles them up as -javaagent script: options. It also automatically bundles in the byteman jar using the boot: agent option. So, using bmjava.sh the previous command line simplifies to

     

    > bmjava.sh -l thread.btm org.my.AppMain2 foo bar baz

     

    Notice that the flag used there is -l for load.

     

    On Windows if you are using byteman release 2.0.1 or later there is an equivalent script called bmjava.bat which you can execute using command bjava. So the previous command simplifies to

     

    > bmjava -l thread.btm org.my.AppMain2 foo bar baz

     

    Note that you need to add the installed bin directory ${BYTEMAN_HOME}/bin to your path in orderto be able to execute the script by name (on windows use %BYETMAN_HOME%/bin)

     

    How Do I Load Rules Into A Running Program?

     

    If you have a long running program you may want to load rules after the program has started running or even unload rules and load new ones. You can do this if you tell Byteman to start its agent listener. The listener also allows you to check the status of loaded rules. To show the listener in use here's another variant of our program, AppMain3.

     

    package org.my;

    import java.io.DataInputStream;

     

    class AppMain3

    {

        public static void main(String[] args)

        {

            try {

            DataInputStream in = new DataInputStream(System.in);

            String next = in.readLine();

            while (next != null && next.length() > 0 && !next.contains("end")) {

            final String arg = next;

            Thread thread = new Thread(arg) {

                public void run() {

                    System.out.println(arg);

                }

                };

            thread.start();

            try {

                thread.join();

            } catch (Exception e){

            }

            next = in.readLine();

            }

        } catch (Exception e) {

        }

        }

    }

     

    This version of the program reads and prints input text until it sees a line containing the String  "end" or and end of file. If we start it using the Byteman listener we can load and unload rules while the program is sitting in a read wait and also check the status of rules as they are parsed, injected into the program, type-checked and executed.

     

    The agent listener is enabled on the java command line using agent option listener:true.  On Linux the command is this

     

    > java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=listener:true,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain3

     

    or on Windows

     

    > java -javaagent:%BYTEMAN_HOME%\lib\byteman.jar=listener:true,boot:%BYTEMAN_HOME%\lib\byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain3

     

    The listener  opens a server socket and then waits for incoming commands. Notice that no rules scripts were specified as agent options so initially when we type in input it is just echoed back

     

    > java  -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=listener:true,boot:${BYTEMAN_HOME}/lib/byteman.jar -Dorg.jboss.byteman.transform.all org.my.AppMain3

    foo

    foo

    bar

    bar

     

    On Linux we  use command script bmsubmit.sh to talk to the agent listener. Calling it with no arguments lists the state of all installed rules

     

    > bmsubmit.sh

    no rules installed

    >

     

    Note that you need to run this in a second command shell -- AppMain3 needs to be still running in order for bmsubmit.sh to be able to talk to the agent via the server socket.

     

    On Windows if you are using Byteman release 2.0.1 or later there is an equivalent script bmsubmit.bat which you can execute usingthe simple command bmsubmit.

     

    > bmsubmit

    no rules installed

    >

     

    If you are using an earlier release you have to use the java command to run the main method of Java class Submit which sends commands to the listener

     

    > java -classpath %BYTEMAN_HOME%\lib\byteman-submit.jar org.jboss.byteman.agent.submit.Submit

    no rules installed

    >

     

    Now we can load our rule script into the running program using bmsubmit.sh

     

    > bmsubmit.sh -l thread.btm

    install rule trace thread start

    >

     

    On Windows you do this using the equivalent script bmsubmit.bat. If you are using a release prior to 2.0.1 you need to execute Submit.main() passing the same argumens

     

    > java -classpath %BYTEMAN_HOME%\lib\byteman-submit.jar org.jboss.byteman.agent.submit.Submit -l thread.btm

    install rule trace thread start

    >

     

    If we check the installed rule state again we see that the rule has been loaded, parsed and and injected into method Thread.start(). If the rule  had failed to parse correctly then injection would have been inhibited and this listing would include details of the parse error.

     

    > bmsubmit.sh

    # File thread.btm line 4

    RULE trace thread start

    CLASS java.lang.Thread

    METHOD start()

    AT ENTRY

    IF true

    DO traceln("*** start for thread: "+ $0.getName())

    ENDRULE

    Transformed in:

    loader: sun.misc.Launcher$AppClassLoader@5acac268

    trigger method: java.lang.Thread.start() void

    >

     

    If we switch back to the running program and type more input we can see the rule being executed

     

    . . .

    bar

    bar

    baz

    *** start for thread: baz

    baz

    mumble

    *** start for thread: mumble

    mumble

     

    How Do I See Which Rules Are Loaded And Compiled?

     

    Running bmsubmit.sh again we can see that the rule has been successfully compiled.

     

    > bmsubmit.sh

    # File thread.btm line 4

    RULE trace thread start

    CLASS java.lang.Thread

    METHOD start()

    AT ENTRY

    IF true

    DO traceln("*** start for thread: "+ $0.getName())

    ENDRULE

    Transformed in:

    loader: sun.misc.Launcher$AppClassLoader@5acac268

    trigger method: java.lang.Thread.start() void

    compiled successfully

    >

     

    This time there is an extra line at the end of the output saying compiled successfully. This means the rule has been type-checked and executed. Type checking only happens when the rule is first triggered --  in this case when Thread.start() is called after typing in the line containing the word baz.  If type checking had failed then execution of the injected code would be inhibited and the listing would include details of the type error. Injected code is only removed when the rule is unloaded.

     

    How Do I Unload Rules?

     

    We can also use bmsubmit.sh (or class Submit on Windows) to unload rules, restoring the original behaviour of Thread.start()

     

    > bmsubmit.sh -u thread.btm

    uninstall RULE trace thread start

    > bmsubmit.sh

    no rules installed

    >

     

    The -u flag is followed by the name of a rule script file. All rules mentioned in the file are unloaded, removing their IF DO code from any methods into which they were injected. If we switch back to the program again it will now revert to just echoing the input text

     

    . . .

    mumble

    *** start for thread: mumble

    mumble

    grumble

    grumble

    bletch

    bletch

    end

    >

     

    n.b. if you want to change the injected code for a rule you don't have to unload and then reload the rule. If you submit a modifed version of a rule script Byteman will remove any existing injected code and reinject the new code.

     

    How Do I Install  The Agent Into A Running Program?

     

    You will sometimes find that you start your program without loading the Byteman agent option only to realise that you would like to use Byteman to check its behaviour. This commonly occurs with a long-running program like the JBoss Application Server when you notice a log message indicating that something has started misbehaving. You don't have to restart the program in order to be able to use Byteman, at least not if you are running your code on a Hotspot, JRockit or OpenJDK JVM. These JVMs all allow you to install an agent program into a running program.

     

    If you are running on Linux then you can use command script bminstall.sh to install the agent program


    > bminstall.sh 13101

    >

     

    n.b. some old (pre-2012) JVMs may not allow agents to be loaded dynamically. Problems have been reported on IBM JVMs running on Linux and on Oracle/OpenJDK running on Windows. However subsequent versions of these JVMs are not known to suffer from this limitation.

     

    On Windows if you are using release 2.0.1 or later you can use the equivalent script bminstall.bat. Otherwise you need to execute Install.main() passing the relevant arguments.

     

    > java -classpath %BYTEMAN_HOME%\lib\byteman-install.jar org.jboss.byteman.agent.install.Install 13101

    >

     

    The numeric argument is the id of the process into which the agent is to be be installed -- obviously you need to supply a value appropriate for the Java program you want to check. Alternatively, you can supply the name of the Java main class of your program (or the jar name if you started it using java -jar myapp.jar). This option is very useful if you want to install the Byteman agent  into a running JBoss Application Server instance. Let's run AppMain3 again but without the -javaagent option and then load up the agent and some rules after it has started running

     

    > java org.my.AppMain3

    foo

    foo

    bar

    bar

     

    Now in another command shell we will install the agent. On Linux

     

    > bminstall -b -Dorg.jboss.byteman.transform.all org.my.AppMain3

    >

     

    bminstall.sh does not load any rule scripts. However, it automatically enables the agent listener, allowing you to submit your rules using bmsubmit.sh. If you try submitting and unsubmitting the rules defined in thread.btm using the commands given in the previous examples you will see them modifying the behaviour of AppMain3.

     

    How Do I Run JBoss AS With Byteman?

     

    If you want to install Byteman into your JBoss Application Server at startup you need to use the -javaagent option. But JBoss AS is run by executing the java command from within a command script, run.sh for AS 4, 5 or 6, standalone.sh or domain.sh for AS 7. So, how do you ensure that these scripts pass the necessary -javaagent options to the JVM?

     

    With AS 4, 5 and 6 you can pass the required argument to the scripts by setting the environment variable JAVA_OPTS. On Linux you might use the following command

     

    set JAVA_OPTS="${JAVA_OPTS} -Dorg.jboss.byteman.transform.all -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:thread.btm,boot:${BYTEMAN_HOME}/lib/byteman.jar,listener:true"

     

    or on Windows

     

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

     

    Notice that the commands insert the current value of JAVA_OPTS retaining any other java options which might already be set.

     

    With AS 7 you normally insert configuration settings for variables like JAVA_OPTS in the configuration files located in the bin subdirectory of your AS7 installation. On Linux you need to edit the files standalone.conf or domain.conf. On  Windows you edit files standalone.conf.bat or domain.conf.bat. If you edit these files you will see there is an obvious place where you can insert the -javaagent option to JAVA_OPTS. You would use a setting just like the examples given above.

     

    If your JBoss AS instance is already running then you can use bminstall.sh to install the agent into the AS. If you know the process id of the JBoss AS process then you just need to pass this process id as argument to bminstall.sh

     

    > bminstall.sh 13101

    >

     

    As mentioned before bminstall.sh allows you to identify the target process using the name of the application main class instead of the process id. So, to install the agent into a running JBoss AS 4, 5 or 6 instance you provide org.jboss.Main as the argument.

     

    > bminstall.sh -b -Dorg.jboss.byteman.transform.all org.jboss.Main

    >


    Argument -b is needed if you want bminstall.sh to load the agent code into the bootstrap classpath. You can also specify system properties to be set by the agent by providing arguments of the form -Dname or -Dname=value.

     

    AS 7 is slightly different because its is started using a command in the format java -jar jarfile. In this case you need to pass bminstall.sh either the process id or the path to the jar file. The jar files used to provide the entry point for JBoss AS7 is jboss-modules.jar. So, you would use the following command to load the agent into a running JBoss AS7 instance

     

    > bminstall.sh -b -Dorg.jboss.byteman.transform.all $JBOSS_HOME/jboss-modules.jar

    >

     

    How Do I Know My Rules Are Correct?

     

    After loading your rules it is useful to rerun  bmsubmit.sh with no arguments to see if they have suffered from parse or type errors. Hwever, it is usually better to identify these problems in advance. Byteman allows you to parse and type check your rules offline before installing them into a Java program. On Linux you run command script bmcheck.sh

     

    > bmcheck.sh thread.btm

    checking rule trace thread start

    parsed rule "trace thread start" for class java.lang.Thread

    type checked rule "trace thread start"

     

    TestScript: no errors

    >

     

    On Windows if you are usiing release 2.0.1 or later  use the equivalent script bmcheck.bat.

    > bmcheck thread.btm

    checking rule trace thread start

    parsed rule "trace thread start" for class java.lang.Thread

    type checked rule "trace thread start"

     

    TestScript: no errors

    >

     

    For earlier releases you can use Java class TestScript

     

    > java -classpath %BYTEMAN_HOME%\lib\byteman.jar org.jboss.byteman.check.TestScript thread.btm

    checking rule trace thread start

    parsed rule "trace thread start" for class java.lang.Thread

    type checked rule "trace thread start"

     

    TestScript: no errors

    >

     

    If the rule script refers to application classes then you need to tell bmcheck.sh where to find them using the -cp flag. So, we need to use this argument to check our first script appmain.btm. But that's not enough. Here's the first rule again

     

    RULE trace main entry

    CLASS AppMain

    METHOD main

    AT ENTRY
    IF true

    DO traceln("entering main")

    ENDRULE

     

    This rule does not use the fully qualified name of the target class. That's ok because the agent notices when org.my.AppMain gets loaded and realises that the rule applies to it. But when we are checking rules offline the application is not run so Byteman does not know which package to use to lookup the class mentioned in the rule. The -p flag can be used to suggest one or more package prefixes for the type checker to try.

     

    > bmcheck.sh -p org.my -cp . appmain.btm

    checking rule trace main entry

    parsed rule "trace main entry" for class org.my.AppMain

    type checked rule "trace main entry"

     

    checking rule trace main exit

    parsed rule "trace main exit" for class org.my.AppMain

    type checked rule "trace main exit"

     

    TestScript: no errors

    >

     

    On Windows if you are using release 2.0.1 or later the -p and -cp options are also accepted by the script bmcheck.bat.

     

    > bmcheck -p org.my -cp . appmain.btm

     

    For earlier releases you have to explicitly add the current directory to the classpath using the java -classpath flag and then pass the -p flag to the check class's main routine by inserting it after the class name and just before the script name(s).

     

    > java -classpath %BYTEMAN_HOME%\lib\byteman.jar;. org.jboss.byteman.check.TestScript -p org.my thread.btm

     

    How Do I Tell If My Rules Are Being Run?

     

    Sometimes you may be unsure whether your rules are being injected correctly. Perhaps the target method is never executed. Perhaps the rule condition is always false. Or maybe a parse or type error is stopping them being executed. If you run Byteman in verbose mode you will see trace output telling you what Byteman is doing. Verbose mode is enabled by setting a system property

     

    > java -Dorg.jboss.byteman.verbose -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:appmain.btm org.my.AppMain foo bar baz

    org.jboss.byteman.agent.Transformer : possible trigger for rule trace main entry in class org.my.AppMain

    RuleTriggerMethodAdapter.injectTriggerPoint : inserting trigger into org.my.AppMain.main(java.lang.String[]) void for rule trace main entry

    org.jboss.byteman.agent.Transformer : inserted trigger for trace main entry in class org.my.AppMain

    org.jboss.byteman.agent.Transformer : possible trigger for rule trace main exit in class org.my.AppMain

    RuleTriggerMethodAdapter.injectTriggerPoint : inserting trigger into org.my.AppMain.main(java.lang.String[]) void for rule trace main exit

    org.jboss.byteman.agent.Transformer : inserted trigger for trace main exit in class org.my.AppMain

    Rule.execute called for trace main entry_0

    HelperManager.install for helper classorg.jboss.byteman.rule.helper.Helper

    calling activated() for helper classorg.jboss.byteman.rule.helper.Helper

    Default helper activated

    calling installed(trace main entry) for helper classorg.jboss.byteman.rule.helper.Helper

    Installed rule using default helper : trace main entry

    trace main entry execute

    entering main

    foo

    bar

    baz

    Rule.execute called for trace main exit_1

    HelperManager.install for helper classorg.jboss.byteman.rule.helper.Helper

    calling installed(trace main exit) for helper classorg.jboss.byteman.rule.helper.Helper

    Installed rule using default helper : trace main exit

    trace main exit execute

    exiting main

    >

     

    The trace is quite verbose but all the information you need is there if you look for it.

     

    • When class AppMain is loaded the trigger locations for each rule is identified and the rule code is injected
    • Next the main method gets called and you can see an execute message for the entry rule (you can ignore the messages about helper activation and rule installation just now or read the Ptrogrammer's Guide if you want them explained)
    • The execute message is followed  by the the enter rule's trace message.
    • The main method prints all its its ouptut
    • Just before it returns there is another execute message for the exit rule (again,  just ignore the messages about  rule installation)
    • The second execute message is followed  by the exit rule's trace message .

     

    How Can I Make My Rules Run Fast?

     

    Normally Byteman executes rules by interpreting the parsed rule code. This is fast enough for most uses but  if you inject code into a tight loop or into  a method which is called frequently then this may slow down your program. You can speed things up a bit by asking Byteman to translate the rule code to bytecode which the JIT compiler can then optimize. This makes the first execution of the rule take longer but  subsequent execution should be a lot faster.

     

    You enable rule compilation by setting system property org.jboss.byteman.compile.to.bytecode when you install the agent. You can do this  on the java command line or when you install the agent using bminstall.sh

     

    > bminstall.sh -Dorg.jboss.byteman.compile.to.bytecode -b org.jboss.Main

    > bmsubmit.sh hornetq-io-rules.btm

    . . .

     

    Where Can I Download The Tutorial Sources?

     

    Here's a zipfile containing the sources for the classes and scripts used in this tutorial. Alternatively you can download the code form the git repository.