BTrace: Introduction, Quick Start, and Detailed Usage Guide
This article introduces BTrace, a lightweight JVM tracing tool, explains its capabilities and limitations, provides step‑by‑step installation and configuration instructions, demonstrates example scripts for monitoring thread pools and other runtime information, and discusses usage scenarios, annotations, and related tools.
Simple Introduction
BTrace is a JVM‑level tracing tool that can output information about a running Java process without affecting its execution. It works for any JVM language and is written as a Java script.
What BTrace can and cannot do
It can output real‑time JVM information such as object states, but it cannot perform operations that modify the JVM state.
Quick Start – Environment Setup
Required components:
btrace 1.3.8.3
beta environment
JDK 1.7.0_45
Tomcat 7
Installation steps:
mkdir btrace
cd btrace
wget http://github.com/btraceio/btrace/releases/download/v1.3.8.3-1/btrace-bin-1.3.8.3.tgz
tar -zxvf btrace-bin-1.3.8.3.tgz
sudo chown -R tomcat:tomcat btrace
export BTRACE_HOME=/xxx/btraceAfter adding BTRACE_HOME to the environment, the script can be executed directly.
Example: Monitoring a ThreadPool
First, view the application PID (e.g., using jps or ps -ef | grep tomcat ). Then run BTrace with a sample script:
sudo -u tomcat ./btrace 2862 ../samples/ThreadStart.javaThe console will display lines such as:
Thread starting InactivityMonitorAsyncTask: java.util.concurrent.ThreadPoolExecutor$Worker@333d7f6a[State=-1, empty queue]If you encounter "Unable to open socket file: target process not responding or HotSpot VM not loaded", run the command with the same user as the target JVM (e.g., sudo -u user btrace … ).
BTrace Script Example (ThreadPoolBtrace.java)
/*
* Copyright (c) 2012 Qunar.com. All Rights Reserved
*/
package com.btrace;
import com.sun.btrace.annotations.*;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class ThreadPoolBtrace {
@Property
private static Map
executorMap = newHashMap();
@Property
private static AtomicInteger lock = newAtomicInteger(0);
@OnMethod(clazz = "java.util.concurrent.ThreadPoolExecutor", method = "execute")
public static void onExecuteRunnable(@Self ThreadPoolExecutor executor) {
if (!containsKey(executorMap, executor) && compareAndSet(lock, 0, 1)) {
println("==== begin ====");
println(str(executor));
Class clazz = classForName("java.util.concurrent.ThreadPoolExecutor");
int corePoolSize = getInt(field(clazz, "corePoolSize", true), executor);
println("corePoolSize size : " + corePoolSize);
printQueueLength(executor);
println("==== end ====");
put(executorMap, executor, size(executorMap));
compareAndSet(lock, 1, 0);
}
}
private static void printQueueLength(ThreadPoolExecutor executor) {
Class clazz = classForName("java.util.concurrent.ThreadPoolExecutor");
BlockingQueue workQueue = (BlockingQueue) get(field(clazz, "workQueue", true), executor);
if (workQueue != null) {
if (matchClazz("java.util.concurrent.ArrayBlockingQueue", workQueue)) {
clazz = classForName("java.util.concurrent.ArrayBlockingQueue");
Object[] itemsInArray = (Object[]) get(field(clazz, "items", true), workQueue);
println("workQueue size : " + itemsInArray.length);
}
if (matchClazz("java.util.concurrent.LinkedBlockingQueue", workQueue)) {
clazz = classForName("java.util.concurrent.LinkedBlockingQueue");
println("workQueue size : " + getInt(field(clazz, "capacity"), workQueue));
}
}
}
private static boolean matchClazz(String clazz, Object instance) {
return compareTo("class " + clazz, str(classOf(instance))) == 0;
}
@OnTimer(5000)
public static void timerLimit() {
clear(executorMap);
}
}Compile and run the script with:
btrace -cp /xxx/jdk1.7.0_79/jre/lib/jfxrt.jar 21854 ../samples/ThreadPoolBtrace.javaBTrace Command Line Parameters
btrace [-I
] [-p
] [-cp
]
[
]Key options: -I for include path, -p to set the agent port (default 2020), -cp for classpath, and script arguments accessible via $ and $length .
Important Notes & Limitations
BTrace must not modify JVM state; it can only read information.
Only BTraceUtils methods are allowed – no object creation, no throwing or catching exceptions, no loops, no synchronized blocks, etc.
All fields in a BTrace class must be static.
Script Annotations
Annotations such as @OnMethod , @OnTimer , @OnExit , @OnError , @OnEvent , and @OnLowMemory define when a tracing method is triggered. Parameter annotations like @Self , @ProbeClassName , @ProbeMethodName , @TargetInstance , @TargetMethodOrField , @Return , and @Duration provide context.
Technical Implementation
BTrace uses the Attach API to connect to a target JVM, the BTrace script engine together with ASM to transform bytecode, and JDK6 instrumentation to inject tracing code. The BTrace client compiles scripts, communicates with a BTrace agent via sockets, and the agent instruments loaded classes on‑the‑fly.
IDE Integration
In VisualVM, install the BTrace WorkBench plugin, then use Trace Application . Alternatively, add BTrace as a Maven dependency, write Java scripts in your IDE, and deploy them to the server.
Common Use Cases
Diagnosing live production issues without restarting the application.
Adding logging to third‑party JARs that cannot be modified.
Capturing stack traces for intermittent problems (e.g., unexpected Full GC).
Similar Tools
HouseMD – a Scala‑based interactive tracing tool (no longer maintained).
Greys – an Alibaba‑maintained interactive Java debugging tool.
Further Resources
Official BTrace documentation: BTrace Annotations
User guide: BTrace User Guide
Various blog posts and articles linked in the original source.
Qunar Tech Salon
Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.