BTrace is a safe, dynamic tracing tool for Java. BTrace works by dynamically (bytecode) instrumenting classes of a running Java program. BTrace inserts tracing actions into the classes of a running Java program and hotswaps the traced program classes.
A BTrace program is a plain Java class that has one or more public static void
methods that
are annotated with BTrace annotations. The annotations are used to
specify traced program "locations" (also known as "probe points"). The tracing actions are
specified inside the static method bodies. These static methods are referred as "action" methods.
To guarantee that the tracing actions are "read-only" (i.e., the trace actions don't change the state of the program traced) and bounded (i.e., trace actions terminate in bounded time), a BTrace program is allowed to do only a restricted set of actions. In particular, a BTrace class
public static
methods
of com.sun.btrace.BTraceUtils
class may be called from a BTrace program.
static
public void
returning methods are allowed for a BTrace class. And all
fields have to be static.
for, while, do..while
)
// import all BTrace annotations
import com.sun.btrace.annotations.*;
// import statics from BTraceUtils class
import static com.sun.btrace.BTraceUtils.*;
// @BTrace annotation tells that this is a BTrace program
@BTrace
public class HelloWorld {
// @OnMethod annotation tells where to probe.
// In this example, we are interested in entry
// into the Thread.start() method.
@OnMethod(
clazz="java.lang.Thread",
method="start"
)
public static void func() {
// println is defined in BTraceUtils
// you can only call the static methods of BTraceUtils
println("about to start a thread!");
}
}
The above BTrace program can be run against a running Java process. This program
will print "about to start a thread!" at the BTrace client whenever the target program
is about to start a thread by Thread.start()
method. There are other
interesting probe points possible. For example, we can insert trace action at
return from a method, exception return from a method, a field get or set within method(s),
object/array creation, line number(s), throwing an exception. Please refer to the
@OnMethod and other annotations for details.
btrace <pid> <btrace-script>
btrace [-I <include-path>] [-p <port>] [-cp <classpath>] <pid> <btrace-script> [<args>]
where
include-path
is a set of include directories that are searched for header files.
BTrace includes a simple preprocess with support for #define, #include and conditional compilation.
It is not like a complete C/C++ preprocessor - but a useful subset. See the sample "ThreadBean.java".
If -I is not specified, BTrace skips the preprocessor invocation step.
port
is the port in which BTrace agent listens. This is optional argument.
classpath
is set of directories, jar files where BTrace searches for classes during compilation.
Default is ".".
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.
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".
It is possible to precompile BTrace program using btracec script. btracec is a javac-like program that takes a BTrace program and produces a .class file.
btracec [-I <include-path>] [-cp <classpath>] [-d <directory>] <one-or-more-BTrace-.java-files>
where
include-path
is a set of include directories that are searched for header files.
BTrace includes a simple preprocess with support for #define, #include and conditional compilation.
It is not like a complete C/C++ preprocessor - but a useful subset. See the sample "ThreadBean.java".
If -I is not specified, BTrace skips the preprocessor invocation step.
classpath
is the classpath used for compiling BTrace program(s). Default is "."
directory
is the output directory where compiled .class files are stored. Default is ".".
So far, we saw how to trace a running Java program. It is also possible to start an application with BTrace agent in it. If you want to start tracing the application from the very "beginning", you may want to start the app with BTrace agent and specify a trace script along with it [i.e., BTrace agent is attach-on-demand loadable as well as pre-loadable agent] You can use the following command to start an app and specify BTrace script file. But, you need to precompile your BTrace script for this kind of usage.
java -javaagent:btrace-agent.jar=script=<pre-compiled-btrace-script> <MainClass> <AppArguments>
When starting the application this way, the trace output goes to a file named <btrace-class-file-name>.btrace
in the current directory. Also, you can avoid starting server for other remote BTrace clients by specifying noServer=true
as an argument to the BTrace agent.
btracer <pre-compiled-btrace.class> <application-main-class> <application-args>
java.awt.Component
or a regular
expression specified within two forward slashes. Refer to the samples
NewComponent.java and
Classload.java. The regular expression can match zero or more
classes in which case all matching classes are instrumented. For example /java\\.awt\\..+/
matches all classes in java.awt package. Also, method name can be a regular expression as well - matching
zero or more methods. Refer to the sample MultiClass.java.
There is another way to abstractly specify traced class(es) and method(s). Traced classes and methods may be
specified by annotation. For example, if the "clazz" attribute is specified as @javax.jws.WebService
BTrace will instrument all classes that are annotated by the WebService annotation. Similarly, method level annotations
may be used to specify methods abstractly. Refer to the sample
WebServiceTracker.java.
It is also possible to combine regular expressions with annotations - like
@/com\\.acme\\..+/
matches any class that is annotated by any annotation that matches the given
regular expression. It is possible to match multiple classes by specifying super type. i.e., match all classes that are subtypes of
a given super type. +java.lang.Runnable
matches all classes implementing java.lang.Runnable
interface. Refer to the sample SubtypeTracer.java.
@com.sun.btrace.annotations.Export
annotation can be used with BTrace fields
(static fields) to specify that the field has to be mapped to a jvmstat counter. Using this, a BTrace
program can expose tracing counters to external jvmstat clients (such as jstat). Refer to the sample
ThreadCounter.java
@com.sun.btrace.annotations.Property
annotation
can be used to flag a specific (static) field as a MBean attribute. If a BTrace class has atleast one static field with
@Property attribute, then a MBean is created and registered with platform MBean server. JMX clients such as VisualVM, jconsole can be
used to view such BTrace MBeans. After attaching BTrace to the target program, you can attach VisualVM or jconsole to the same
program and view the newly created BTrace MBean. With VisualVM and jconsole, you can use MBeans tab to view the BTrace domain and
check out it's attributes. Refer to the samples ThreadCounterBean and
HistogramBean.java.
@com.sun.btrace.annotations.TLS
annotation can be used with BTrace fields (static
fields) to specify that the field is a thread local field. Each Java thread gets a separate "copy" of
the field. These thread local fields may be used by BTrace programs to identify whether we reached multiple
probe actions from the same thread or not. Refer to the samples
OnThrow.java and
WebServiceTracker.java
@com.sun.btrace.annotations.DTrace
annotation can be used to associate a simple one-liner D-script (inlined in BTrace Java class) with
the BTrace program. Refer to the sample DTraceInline.java.
@com.sun.btrace.annotations.DTraceRef
annotation can be used to associate a D-script (stored in a separate file) with the BTrace
program. Refer to the sample DTraceRefDemo.java.
@com.sun.btrace.annotations.BTrace
annotation must be used to designate a given Java class as a BTrace program. This annotation is
enforced by the BTrace compiler as well as by the BTrace agent.
Solaris DTrace is a dynamic, safe tracing system for Solaris programs - both kernel and user land programs. Because of the obvious parallels b/w DTrace and BTrace, it is natural to expect integration b/w BTrace and DTrace. There are two ways in which BTrace is integrated with DTrace.
dtraceProbe
-- see BTraceUtils javadoc referred above.
For this feature to work, you need to be running on Solaris 10 or beyond. For other platforms (Solaris 9 or below
or any other OS), dtraceProbe()
will be a no-op.
One lines about samples:
defineClass
returns) by any userdefined
class loader.
deadlock()
built-in function.
File{Input/Output}Stream
constructor entry points.
javax.swing.JComponent
objects created by an app - histogram by subclass name and count).
@Property
annotation.
printVmArguments()
, printProperties()
and
printEnv()
built-in functions.
dumpHeap()
built-in function to dump (hprof binary format)
heap dump of the target application.
jstackAll()
built-in function to print stack traces of
all the threads.
field()
and objectValue()
built-in functions.
clazz
and method
fields of @OnMethod
annotation.
java.awt.Component
creation and increments
a counter and prints the counter based on a timer.
@OnExit
probe and exit(int)
built-in function.
@OnTimer
) in a BTrace program.
URL.openConnection
returns
successfully. This program uses jurls.d
D-script as well (to show histogram of URLs opened via DTrace).