如果在分析线上问题时,发现日志打的不全,无法定位怎么办?添加日志重新上线,不是一个好方法,特别是调试时,可能要反复添加日志来定位问题或者线上出现的问题很难再复现,根本就没有机会添加日志再继续分析,这时就可以使用btrace。
btrace是jvm实时监控的工具,是性能调优和线上问题诊断的神器,btrace基于动态字节码修改技术,来实现对运行时的java程序进行跟踪和替换。也就是说可以在不重启jvm的情况下监控系统运行情况,获取jvm运行时的数据信息,比如方法参数、返回值、全局变量、堆栈信息等。
首先可以对方法进行定位拦截,获取方法的入参、返回值、执行时间等信息。
第二可以查看某类对象的创建情况。
第三可以对内存使用情况进行统计,可以查看对象大小。
第四可以查看同步块执行情况。
注意问题:
1.不恰当的使用btrace可能导致jvm崩溃
2.btrace做的修改会一直生效的,直到重启jvm后,才会消除
3.可以通过设置jvm参数取消btrace的安全限制
下面版本是linux版本,实际场景中应该先在window桌面版(https://blog.csdn.net/wwd0501/article/details/94482419)中调试后,再部署到线上环境中。官方声明,不恰当的使用BTrace可能导致JVM崩溃,如在BTrace脚本使用错误的class文件,所以在上生产环境之前,务必在本地充分的验证脚本的正确性。
一、 安装JDK
JAVA_HOME=/usr/java/jdk1.8.0_111
export JAVA_HOME
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
二、 安装BTrace
1)下载地址:https://github.com/btraceio/btrace/releases/tag/v1.3.11.3 (btrace-bin-1.3.11.3.tgz或btrace-bin-1.3.11.3.zip)
2)解压缩
tar -zxvf btrace-bin-1.3.11.3.tgz
3)设置环境变量至当前用户目录下的.profile
添加如下配置:
BTRACE_HOME=/data/soft/btrace
export BTRACE_HOME
export PATH=$PATH:$BTRACE_HOME/bin
执行source .profile
三、 示例代码
public class Calculator {
private int c = 1;
public int add(int a, int b) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return a + b;
}
}
import java.util.Random;
public class BTraceDemo {
public static void main(String[] args) {
Calculator calculator = new Calculator();
Random random = new Random();
while (true) {
System.out.println(calculator.add(random.nextInt(10), random.nextInt(10)));
}
}
}
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class BTraceTest {
@OnMethod(
clazz = "Calculator",
method = "add",
location = @Location(Kind.RETURN)
)
public static void trace1(int a, int b, @Return int sum) {
println("trace1:a=" + a + ",b=" + b + ",sum=" + sum);
}
}
注意:若是有包路径,clazz要写全路径,比如:clazz="com.test.Calculator"
1、执行javac BTraceDemo.java
2、执行java BTraceDemo
3、查看BTraceDemo进程号
4、执行btrace 1792 BTraceTest.java
1792是BTraceDemo的进程ID
trace1方法实现对Calculator类的add方法的入参和返回值进行追踪,结果如下。
若是出现btrace报错:Port 2020 unavailable
原因是btrace会在remote JVM(pid:122810)agent开启一个远程socketserver,默认端口是2020,正好我这台服务器有多个JVM实例,当我在第一个JVM上执行之后,第一个就会报错。正确的做法是:btrace -p 2021 1972 T.java 。
在实际项目中,直接就是监控我们的项目进程ID
package com.test.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.test.Calculator;
@RestController
@RequestMapping("/test/")
public class TestController {
@RequestMapping("/demo")
public String demo(int a , int b) {
Calculator cal = new Calculator();
return cal.add(a, b) + "";
}
}
package com.test;
public class Calculator {
private int c = 1;
public int add(int a, int b) {
c++;
return a + b;
}
}
/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
/* 此为btrace程序*/
@BTrace
public class TracingScript {
/* put your code here */
@OnMethod(
clazz = "com.test.Calculator",
method = "add",
location = @Location(Kind.RETURN)
)
public static void func(int a,int b,@Return int result,@Duration long time){
println("调用堆栈:");
jstack();
println(strcat("方法参数A:",str(a)));
println(strcat("方法参数B:",str(b)));
println("cost time : " + time);
println(strcat("方法结果:",str(result)));
println();
}
}
先启动项目,例如上面的两个类在wareic项目中
然后再执行btrace 21362 TracingScript.java
(btrace -v 21362 TracingScript.java 类似dedug模式,打印的信息更详细。)
此时访问http://localhost:8080/test/demo?a=1&b=2,就可以看到追踪信息。
windows桌面版:https://blog.csdn.net/wwd0501/article/details/94482419,可以先在本地多测试几遍,然后再上线。