• BTrace:线上问题排查工具


    BTrace简介

    GitHub地址:BTrace

    下载地址:v1.3.11.3

    官方使用教程:Btrace使用教程

    使用场景

    BTrace 是一个事后工具,所谓事后工具就是在服务已经上线了,但是发现存在以下问题的时候,可以用 BTrace。

    1. 比如哪些方法执行太慢,例如监控执行时间超过1s的方法
    2. 查看哪些方法调用了 System.gc() ,调用栈是怎样的
    3. 查看方法参数或对象属性
    4. 哪些方法发生了异常

    多说一点,为了更好解决问题,最好还要配合事前准备和进行中监控,事前准备就是埋点嘛,在一些可能出现问题的方法中进行日志输出,进行中监控就是利用一些实时监控工具,例如 VisualVM 、jmc 这些带界面的工具或者 jdk 提供的命令行工具等,再高级一点的就是利用 Graphite 这样的Metrics 工具配合 web 界面展示出来。

    使用限制

    为了保证trace语句只读,最小化对被检测程序造成影响, BTrace对trace脚本有一些限制(比如不能改变被trace代码中的状态)

    • BTrace class不能新建类, 新建数组, 抛异常, 捕获异常,
    • 不能调用实例方法以及静态方法(com.sun.btrace.BTraceUtils除外)
    • 不能将目标程序和对象赋值给BTrace的实例和静态field
    • 不能定义外部, 内部, 匿名, 本地类
    • 不能有同步块和方法
    • 不能有循环
    • 不能实现接口, 不能扩展类
    • 不能使用assert语句, 不能使用class字面值

    Windows安装

    下载对应的zip文件,解压

    配置环境变量:

    BTRACE_HOME=D:Program Filestrace-bin
    

    Path内添加:

    %BTRACE_HOME%in
    

    查看版本:

    $ btrace --version
    BTrace v.1.3.11.3 (20181217)
    

    Linux安装

    第一步,在github 上下载 releases 版 btrace-bin-1.3.9.tgz,zip 版的没有 build 目录。

    第二步,解压 btrace-bin-1.3.9.tgz 到一个目录即可,例如 /home/hongda/soft/btrace , 到这一步其实就可以用了,只是执行脚本的时候需要在 btrace 命令前加上绝对路径,如果想在任意目录可执行,进行下一步第三步。

    第三步,配置环境变量,配置的环境变量包括 JAVA_HOME和 BTRACE_HOME 。

    例如我的配置如下:

    export JAVA_HOME=/home/hongda/soft/jdk1.8.0_111
    export JRE_HOME=${JAVA_HOME}/jre
    export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib 
    export PATH=${JAVA_HOME}/bin:$PATH
    export BTRACE_HOME=/home/hongda/soft/btrace
    export PATH=$PATH:$BTRACE_HOME/bin
    

    之后执行命令 source /etc/profile ,使环境变量立即生效。接下来在任意目录执行 btrace命令,都可以执行成功了。

    BTrace项目配置

    项目中pom.xml引用新增:

     <dependency>
                <groupId>com.sun.btrace</groupId>
                <artifactId>btrace-agent</artifactId>
                <version>1.3.11.3</version>
                <type>jar</type>
                <scope>system</scope>
                <systemPath>${basedir}/libs/btrace/btrace-agent.jar</systemPath>
            </dependency>
            <dependency>
                <groupId>com.sun.btrace</groupId>
                <artifactId>btrace-boot</artifactId>
                <version>1.3.11.3</version>
                <type>jar</type>
                <scope>system</scope>
                <systemPath>${basedir}/libs/btrace/btrace-boot.jar</systemPath>
            </dependency>
            <dependency>
                <groupId>com.sun.btrace</groupId>
                <artifactId>btrace-client</artifactId>
                <version>1.3.11.3</version>
                <type>jar</type>
                <scope>system</scope>
                <systemPath>${basedir}/libs/btrace/btrace-client.jar</systemPath>
            </dependency>
    

    或者直接安装到本地:

    mvn install:install-file -Dfile=D:GitHello-Worldlibstracetrace-boot.jar -DgroupId=com.sun.btrace -DartifactId=btrace-boot -Dversion=1.3.11.3 -Dpackaging=jar
    
    mvn install:install-file -Dfile=D:GitHello-Worldlibstracetrace-agent.jar -DgroupId=com.sun.btrace -DartifactId=btrace-agent -Dversion=1.3.11.3 -Dpackaging=jar
    
    mvn install:install-file -Dfile=D:GitHello-Worldlibstracetrace-client.jar -DgroupId=com.sun.btrace -DartifactId=btrace-client -Dversion=1.3.11.3 -Dpackaging=jar
    

    文件夹符合无所谓,都可以

    mvn install:install-file -Dfile=D:/Git/Hello-World/libs/btrace/btrace-boot.jar -DgroupId=com.sun.btrace -DartifactId=btrace-boot -Dversion=1.3.11.3 -Dpackaging=jar
    

    上面这句也可以,然后修改pom.xml配置即可

    不能够使用Program Files,发现命令里面有空格就报错

    btrace预编译:

    预编译:执行之前可以用预编译命令检查脚本的正确性,预编译命令为 btracec,它是一个 javac-like 命令

    D:GitHello-Worldsrcmainjavacomqhongtrace (master -> origin)
    $ btracec AllCalls1.java
    

    btrace执行命令:

    btrace 10860 NumberUtilBTrace.java
    

    10860是要排查问题的项目运行的pid

    如果要保存到本地文件中,可以使用转向命令

    btrace 10860 NumberUtilBTrace.java > mylog.log
    

    按ctrl + c ,会给出退出提示,再按 1 退出

    如何定位

    定位方法

    @OnMethod(clazz="/javax\.swing\..*/", method="/.*/")
    public static void swingMethods( @ProbeClassName String probeClass, @ProbeMethodName String probeMethod) {
       print("entered " + probeClass + "."  + probeMethod);
    }
    

    正则表达式在两个"/" 之间,例如下面的例子,监控 javax.swing 包下的所有方法,注意正式环境中,范围尽可能小一点,太大了性能会有影响。

    通过在拦截函数的定义里注入@ProbeClassName String probeClass, @ProbeMethodName String probeMethod 参数,告诉脚本实际匹配到的类和方法名。

    定位接口或继承类

    @OnMethod(clazz="+com.kite.base", method="doSome")
    

    定位注解

    @OnMethod(clazz="@javax.jws.WebService", method="@javax.jws.WebMethod")
    

    如何拦截

    方法进入返回拦截(Kind.Entry与Kind.Return)

    分别表示函数的开始和返回,不写 location 的情况下,默认为 Kind.Entry,仅获取参数值,可以用 Kind.Entry ,要获取返回值或执行时间就要用 Kind.Return

    方法异常拦截(Kind.Error, Kind.Throw和 Kind.Catch)

    表示异常被 throw 、异常被捕获还有异常发生但是没有被捕获的情况,在拦截函数的参数定义里注入一个Throwable的参数,代表异常

    方法调用其他方法拦截(Kind.Call)

    @Self 表示当前监控的函数所在类,如果是静态类则为空

    @TargetInstance 表示函数中调用的方法或属性所在的类,如果是静态方法则为空

    @TargetMethodOrField 表示调用的方法或属性,如果要获取执行时间,那么 where 必须设置为 Where.AFTER

    方法是否执行某行数(Kind.Line)

    具体操作

    方法请求返回参数:

    import static com.sun.btrace.BTraceUtils.println;
    
    import com.sun.btrace.AnyType;
    import com.sun.btrace.annotations.BTrace;
    import com.sun.btrace.annotations.Kind;
    import com.sun.btrace.annotations.Location;
    import com.sun.btrace.annotations.OnMethod;
    import com.sun.btrace.annotations.ProbeClassName;
    import com.sun.btrace.annotations.ProbeMethodName;
    import com.sun.btrace.annotations.Return;
    
    /**
     * Created by qhong on 2019/3/6 16:50
     **/
    @BTrace
    public class AllMethodTrace {
    
    	@OnMethod(
    			clazz="/com\.shitou\.huishi\.service\..*/",
    			method="queryRiskApproveList",
    			location=@Location(Kind.RETURN)
    	)
    	public static void anyRead(@ProbeClassName String pcn,
    							   @ProbeMethodName String pmn,
    							   @Return AnyType result)
    	{
    		println("ClassName: " + pcn);
    		println("MethodName: " + pmn);
    		println("ResultValue: " + result);
    		println();
    	}
    
    	@OnMethod(
    			clazz="/com\.shitou\.huishi\.service\..*/",
    			method="queryRiskApproveList",
    			location=@Location(Kind.ENTRY)
    	)
    	public static void onBind(@ProbeClassName String pcn,
    							   @ProbeMethodName String pmn,
    							   Object params)
    	{
    		println("ClassName: " + pcn);
    		println("MethodName: " + pmn);
    		println("EntryValue: " + params);
    		println();
    	}
    }
    

    命令:

    D:GitHello-Worldsrcmainjavacomqhongtracehandmovement (master -> origin)
    $ btrace 26592 AllMethodTrace.java  >huishi.log
    

    huishi.log:

    ClassName: com.shitou.huishi.service.web.RiskApproveServiceImpl
    MethodName: queryRiskApproveList
    EntryValue: QueryRiskApproveListRequest(orgSource=JSY, productType=null, subjectName=东, subjectNo=, pageIndex=1, pageSize=30)
    
    ClassName: com.shitou.huishi.service.web.RiskApproveServiceImpl
    MethodName: queryRiskApproveList
    ResultValue: DataResponse(data=RiskApproveListResponse(totalCount=2, list=[QueryRiskApproveListResponse(taskType=风控审批, taskTypeStatus=0, loanOrderId=BO119643622212763658, orderType=非授信, orgName=及时雨, productName=小微企业经营贷, subjectName=中国石化, subjectNo=122334563748992, subjectNoType=null, operationName=部门经理, modifyTime=Wed Sep 19 16:16:04 CST 2018, updateTime=2018-09-19 16:16:04, taskId=291570, processInstanceId=288773, customerName=wangky, applyAmount=16000000.00, alertMessage=null, buttonStatus=[1, 2, 0], loanPlatform=null, IsFillData=false, approveStatus=a-1), QueryRiskApproveListResponse(taskType=风控审批, taskTypeStatus=0, loanOrderId=BO119643672992153605, orderType=非授信, orgName=及时雨, productName=小微企业经营贷, subjectName=东风标致, subjectNo=37889999004, subjectNoType=null, operationName=部门经理, modifyTime=Fri Dec 28 18:32:23 CST 2018, updateTime=2018-12-28 18:32:23, taskId=320560, processInstanceId=288785, customerName=wangky, applyAmount=16008000.00, alertMessage=null, buttonStatus=[1], loanPlatform=null, IsFillData=true, approveStatus=a-0)]))
    

    参考:

    【基本功】Java动态追踪技术探究

    BTrace : Java 线上问题排查神器

    基于Btrace的监控调试

    Btrace代码生成工具

  • 相关阅读:
    delphi 让子窗体显示最大化
    Delphi 中拖动无边框窗口的5种方法
    Delphi 非主窗体(即子窗体)在任务栏显示按钮
    电脑快捷键大全
    picpick快捷键
    is()
    animate()
    :animated
    css() 方法返回或设置匹配的元素的一个或多个样式属性。
    outerWidth()
  • 原文地址:https://www.cnblogs.com/hongdada/p/10479412.html
Copyright © 2020-2023  润新知