BTrace 实战案例详解
BTrace 是 Java 动态追踪工具,可以在不重启应用的情况下对运行中的 Java 程序进行安全的热插拔监控。

环境准备
# 下载 BTrace wget https://github.com/btraceio/btrace/releases/download/v2.2.0/btrace-v2.2.0-bin.tar.gz tar -xzf btrace-v2.2.0-bin.tar.gz # 配置环境变量 export BTRACE_HOME=/path/to/btrace-v2.2.0 export PATH=$PATH:$BTRACE_HOME/bin # 查看帮助 btrace -h
基础案例集合
案例 1:方法调用耗时统计
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class MethodTimeTracer {
// 计时用的线程局部变量
@TLS
private static long startTime;
// 监控指定方法
@OnMethod(
clazz = "com.example.service.UserService",
method = "getUserById",
location = @Location(Kind.ENTRY)
)
public static void onEntry(@ProbeMethodName String methodName) {
startTime = timeMillis();
println("=== Enter " + methodName + " ===");
println("Start Time: " + startTime);
}
@OnMethod(
clazz = "com.example.service.UserService",
method = "getUserById",
location = @Location(Kind.RETURN)
)
public static void onReturn(@ProbeMethodName String methodName,
@Duration long duration) {
println("=== Exit " + methodName + " ===");
println("Cost: " + (timeMillis() - startTime) + " ms");
println("Duration: " + duration + " ns");
println("================");
}
}
案例 2:参数和返回值跟踪
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class MethodArgTracer {
@OnMethod(
clazz = "com.example.service.OrderService",
method = "createOrder",
location = @Location(Kind.ENTRY)
)
public static void traceEntry(@Self Object instance,
String orderId,
double amount,
int userId) {
println("=== Create Order ===");
println("Instance: " + instance.getClass().getName());
println("OrderId: " + orderId);
println("Amount: " + amount);
println("UserId: " + userId);
}
@OnMethod(
clazz = "com.example.service.OrderService",
method = "createOrder",
location = @Location(Kind.RETURN)
)
public static void traceReturn(@Return boolean result) {
println("Create Order Result: " + result);
println("===================");
}
// 捕获异常
@OnMethod(
clazz = "com.example.service.OrderService",
method = "createOrder",
location = @Location(Kind.ERROR)
)
public static void traceError(@Thrown Throwable e) {
println("Create Order Error: " + e);
printlnStack();
}
}
案例 3:线程信息监控
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class ThreadMonitor {
// 监控线程启动
@OnMethod(
clazz = "java.lang.Thread",
method = "start"
)
public static void onThreadStart(@Self Thread thread) {
println("=== Thread Started ===");
println("Name: " + thread.getName());
println("Priority: " + thread.getPriority());
println("======================");
}
// 定期打印所有线程状态
@OnTimer(10000) // 每10秒执行一次
public static void printThreadInfo() {
println("=== Thread Dump ===");
Thread[] threads = Thread.getAllStackTraces().keySet().toArray(new Thread[0]);
for (Thread t : threads) {
if (t.isAlive()) {
println("Thread: " + t.getName() +
", State: " + t.getState() +
", Daemon: " + t.isDaemon());
}
}
}
// 监控线程池
@OnMethod(
clazz = "java.util.concurrent.ThreadPoolExecutor",
method = "execute"
)
public static void onTaskSubmit(@Self ThreadPoolExecutor executor) {
println("=== Task Submitted ===");
println("Active Count: " + executor.getActiveCount());
println("Queue Size: " + executor.getQueue().size());
println("Pool Size: " + executor.getPoolSize());
println("Core Pool Size: " + executor.getCorePoolSize());
println("Max Pool Size: " + executor.getMaximumPoolSize());
println("Completed Tasks: " + executor.getCompletedTaskCount());
}
}
高级案例
案例 4:内存和 GC 监控
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class MemoryMonitor {
// 每5秒打印一次内存使用
@OnTimer(5000)
public static void printMemory() {
println("=== Memory Usage ===");
Runtime runtime = Runtime.getRuntime();
long total = runtime.totalMemory();
long free = runtime.freeMemory();
long used = total - free;
long max = runtime.maxMemory();
println("Total: " + formatMemory(total));
println("Used: " + formatMemory(used));
println("Free: " + formatMemory(free));
println("Max: " + formatMemory(max));
println("Usage: " + (used * 100 / max) + "%");
println("====================");
}
private static String formatMemory(long bytes) {
return (bytes / (1024 * 1024)) + " MB";
}
// 监控对象分配
@OnMethod(
clazz = "java.lang.OutOfMemoryError",
method = "<init>"
)
public static void onOOM(@Self OutOfMemoryError e) {
println("!!! OutOfMemoryError !!!");
println(e.getMessage());
printlnStack();
// 触发一次完整的堆转储
jstack();
}
// 监控垃圾回收
@OnMethod(
clazz = "java.lang.System",
method = "gc"
)
public static void onGC() {
println("=== System.gc() called ===");
printMemory();
}
}
案例 5:HTTP 请求监控(Spring Boot)
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class HttpMonitor {
@TLS
private static String requestId;
// 监控 Controller 层
@OnMethod(
clazz = "org.springframework.web.servlet.DispatcherServlet",
method = "doDispatch"
)
public static void onRequest(@Self Object servlet,
@ProbeMethodName String method) {
requestId = Strings.strcat("Req-", String.valueOf(timeMillis()));
println("=== " + requestId + " ===");
println("Request received at: " + new Date());
}
@OnMethod(
clazz = "org.springframework.web.servlet.DispatcherServlet",
method = "doDispatch",
location = @Location(Kind.RETURN)
)
public static void onRequestReturn(@Duration long duration) {
println("Request completed in: " + (duration / 1000000) + " ms");
println("======================");
}
// 监控特定接口
@OnMethod(
clazz = "com.example.controller.UserController",
method = "/api/users"
)
public static void onUserApi(@Self Object controller,
@ProbeMethodName String method) {
println("=== User API Called ===");
println("Controller: " + controller.getClass().getName());
println("Method: " + method);
}
}
案例 6:JDBC 连接监控
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class JDBCMonitor {
private static Map<Object, Object> connectionMap = new HashMap<Object, Object>();
// 监控 Connection 创建
@OnMethod(
clazz = "com.mysql.cj.jdbc.ConnectionImpl",
method = "<init>"
)
public static void onConnectionCreate(@Self Object connection) {
println("=== Connection Created ===");
println("Connection: " + connection);
connectionMap.put(identity(connection), currentTime());
}
// 监控 SQL 执行
@OnMethod(
clazz = "com.mysql.cj.jdbc.StatementImpl",
method = "executeQuery"
)
public static void onQuery(@Self Object statement,
String sql) {
println("=== SQL Query ===");
println("SQL: " + sql);
println("Time: " + currentTime());
// 获取连接信息
if (statement != null) {
println("Statement: " + statement.getClass().getName());
}
}
// 监控连接关闭
@OnMethod(
clazz = "com.mysql.cj.jdbc.ConnectionImpl",
method = "close"
)
public static void onConnectionClose(@Self Object connection) {
println("=== Connection Closed ===");
println("Connection: " + connection);
connectionMap.remove(identity(connection));
println("Active Connections: " + connectionMap.size());
}
// 定期检查活跃连接
@OnTimer(60000)
public static void checkConnections() {
println("=== Active Connections: " + connectionMap.size() + " ===");
if (connectionMap.size() > 10) {
println("WARNING: Too many active connections!");
}
}
}
案例 7:监控特定异常
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class ExceptionMonitor {
// 监控所有异常
@OnMethod(
clazz = "java.lang.Throwable",
method = "<init>"
)
public static void onException(@Self Throwable t) {
String className = t.getClass().getName();
// 过滤特定异常
if (className.contains("BusinessException") ||
className.contains("SystemException")) {
println("=== Exception Created ===");
println("Type: " + className);
println("Message: " + t.getMessage());
// 直接打印堆栈
jstack();
// 简单的计数器
incrementAndPrint("ExceptionCount");
}
}
@Property
private static long exceptionCount;
private static void incrementAndPrint(String name) {
exceptionCount++;
println(name + ": " + exceptionCount);
}
// 监控异常抛出点
@OnMethod(
clazz = "/com\\.example\\..*/",
method = "/.*/"
)
public static void traceMethod(@ProbeClassName String className,
@ProbeMethodName String methodName,
@Self Object instance) {
if (instance instanceof Throwable) {
println("Throwing in: " + className + "." + methodName);
}
}
}
实用脚本模式
案例 8:性能瓶颈分析
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class PerformanceAnalyzer {
@TLS
private static Map<String, Long> methodTimes = new HashMap<String, Long>();
@TLS
private static Map<String, Integer> methodCounts = new HashMap<String, Integer>();
@OnMethod(
clazz = "/com\\.example\\..*/",
method = "/.*/"
)
public static void traceMethod(@ProbeClassName String className,
@ProbeMethodName String methodName) {
String key = className + "." + methodName;
methodCounts.put(key,
methodCounts.containsKey(key) ?
methodCounts.get(key) + 1 : 1);
if (methodCounts.get(key) % 100 == 0) {
println("Method " + key + " called " +
methodCounts.get(key) + " times");
}
}
// 定期输出热点方法
@OnTimer(60000)
public static void printHotspots() {
println("=== Method Call Counts ===");
for (Map.Entry<String, Integer> entry : methodCounts.entrySet()) {
if (entry.getValue() > 100) {
println(entry.getKey() + ": " + entry.getValue() + " calls);
}
}
}
}
案例 9:线上问题定位
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class ProblemDiagnoser {
// 监控死锁
@OnTimer(30000)
public static void detectDeadlock() {
println("=== Deadlock Detection ===");
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();
if (deadlockedThreads != null) {
println("!!! DEADLOCK DETECTED !!!");
ThreadInfo[] threadInfo = threadMXBean.getThreadInfo(deadlockedThreads);
for (ThreadInfo info : threadInfo) {
println("Thread: " + info.getThreadName());
println("State: " + info.getThreadState());
println("Lock: " + info.getLockName());
println("==================================");
}
}
}
// 监控 CPU 使用率高的线程
@OnTimer(10000)
public static void monitorCPU() {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
long[] threadIds = threadMXBean.getAllThreadIds();
for (long id : threadIds) {
long cpuTime = threadMXBean.getThreadCpuTime(id);
if (cpuTime > 1000000000) { // CPU时间超过1秒
ThreadInfo threadInfo = threadMXBean.getThreadInfo(id);
println("High CPU Thread: " + threadInfo.getThreadName());
println("CPU Time: " + (cpuTime / 1000000000) + "s");
printlnThreadStack(threadInfo);
}
}
}
}
执行案例
# 查找进程 ID jps -l # 执行 BTrace 脚本(阻塞模式) btrace <pid> MethodTimeTracer.java # 后台执行 btrace -p <port> <pid> MethodTimeTracer.java & # 使用退出命令 btrace -o /tmp/result.txt <pid> MethodTimeTracer.java # 带参数的执行 btrace -d <classpath> <pid> MethodTimeTracer.java
注意事项
# 1. 生产环境安全模式(只读操作) btrace -c <pid> MethodTimeTracer.java # 2. 限制输出 btrace -w <pid> MethodTimeTracer.java # 只输出到当前窗口 btrace -s <pid> MethodTimeTracer.java # 同步模式 # 3. 优雅退出 jcmd <pid> BTrace.stop
这些案例覆盖了 BTrace 的主要应用场景,实际使用时需要根据业务场景调整类名、方法名和监控逻辑,在使用生产环境时,建议先在测试环境验证脚本的正确性和安全性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播