Thursday, August 06, 2009

BTrace – A dynamic trace tool for Java platform

BTrace (where the ‘B’ stands for bytecode) is an open source tool hosted on java.net, where you can find extensive documentation and samples. It is conceptually similar to the much-talked-about Solaris DTrace platform, but can be used on any Java platform/app.

The main BTrace concept is that of dynamically connecting to a running Java application (or server) to attach short “scripts” which log a range of events and infos such as

  • method calls;
  • execution times;
  • constructor invocation;
  • available memory;

In a way, BTrace scripts are very similar to AOP’s aspects, but can be attached to any existing Java code (or better, bytecode) at runtime and without any configuration or modification at development time.

Script execution is tied to several situations

  • reaching a specific line number;
  • invoking a given method;
  • returning from a method;
  • invoking system calls (e.g. exit);
  • recurring timer (period execution at fixed intervals);
  • and many more

The scripts are simply Java classes which take advantage of methods from the btrace API, and are configured by using simple but powerful annotations. Here you are an hello world script which traces session creation in hibernate:

   1: // import BTrace annotations
   2: import com.sun.btrace.annotations.*;
   3: // import logging methods
   4: import static com.sun.btrace.BTraceUtils.*;
   5:  
   6: @BTrace
   7: public class DemoAppTrace 
   8: {
   9:     // store the entry time in this thread local
  10:     @TLS private static long startTime;
  11:  
  12:     // probe the openSession() method of Hibernate SessionFactory
  13:     @OnMethod(clazz=”org.hibernate.SessionFactory”,    method=”openSession”)
  14:     public static void onOpenTrace() 
  15:     {
  16:         // you can only log using the static println method from BTraceUtils
  17:         println(”Hibernate: opening a new session…”);
  18:         
  19:         // the BTrace built-in strcat function is needed to avoid the overhead of string concatenation
  20:         println(strcat(strcat(name(probeClass()), "."), probeMethod()));
  21:         startTime = timeMillis();
  22:     }
  23:  
  24:     // probe the completion of openSession() method 
  25:     // the Kind.RTURN tell the BTrace to probe the end of the method execution 
  26:     @OnMethod(clazz=”org.hibernate.SessionFactory”,    method=”openSession”, location=@Location(Kind.RETURN))
  27:     public static void onReturnTrace() 
  28:     {
  29:         // the BTrace built-in strcat function is needed/used to avoid the overhead of string concatenation
  30:         println(strcat("Time taken (msec) ", str(timeMillis() - startTime)));
  31:     }
  32: }

How to run – as explained in their documentation:

Steps to run BTrace
  1. Find the process id of the target Java process that you want to trace. You can use jps tool to find the pid.
  2. Write a BTrace program - you may want to start modifying one of the samples.
  3. Run btrace tool by the following command line:
       btrace <pid> <btrace-script>
BTrace Command Line
BTrace is run using the command line tool btrace as shown below:
    btrace [-p <port>] [-cp <path>] <pid> <btrace-script> [<args>]
where
  • pid is the process id of the traced Java program
  • btrace-script is the trace program. If it is a ".java", then it is compiled before submission. Or else, it is assumed to be pre-compiled [i.e., it has to be a .class] and submitted.
optional
  • port is the server socket port at which BTrace agent listens for clients. Default is 2020.
  • path is the classpath used for compiling BTrace program. Default is ".".
  • args is command line arguments passed to BTrace program. BTrace program can access these using the built-in functions "$" and "$length".

No comments: