此文已由作者易国强授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

1 btrace简介

BTrace是一个非常不错的java诊断工具。BTrace 中的B表示bytecode,它是在字节码层面上对代码进行trace ,通过在运行中的java类中注入trace代码, 并对运行中的目标程序进行热交换(hotswap)来达到对代码的跟踪 。BTrace应用较为广泛的原因应该是其安全性和无侵入性,以及热交互技术,使得我们无需启动Agent的情况下动态跟踪分析,其安全性不会导致对目标Java进程的任何破坏性影响,使得BTrace成为我们线上产品问题定位的利器。无侵入性无需我们对原有代码做任何修改,降低上线风险和测试成本,并且无需重启启动目标Java进程进行Agent加载即可动态分析和跟踪目标程序,可以说BTrace可以满足大部分的应用场景。

2 btrace原理

总体来说,BTrace是基于动态字节码修改技术(Hotswap)来实现运行时java程序的跟踪和替换。大体的原理如下所示:

Client(Java compile api + attach api) + Agent(脚本解析引擎 + ASM + JDK6 Instumentation) + Socket

BTrace的入口类在https://gi

thub.com/btraceio/btrace/blob/master/src/share/classes/com/sun/btrace/client/Main.java中。在其main方法中,可以看到起最终的核心逻辑是在https://github.com/btraceio/btrace/blob/master/src/share/classes/com/sun/btrace/client/Client.java中。方法调用如下:

  • client.compile

  • client.attach

  • client.submit

具体来说,针对官网给出的示例进行说明,有以下脚本:

import com.sun.btrace.annotations.*;import static com.sun.btrace.BTraceUtils.*;@BTracepublic class HelloWorld {    @OnMethod(
        clazz="java.lang.Thread",
        method="start"
    )    public static void func() {
        println("about to start a thread!");
    }
}

@OnMethod告诉Btrace解析引擎需要代理的类和方法。 这个例子的作用是在需要监控的程序中的java.lang.Thread类的任意一个对象调用 start 方法后,都会调用func方法。首先client会编译上述脚本,然后client.attach使用java的attach api将agent动态attach到目标jvm进程中,最后client的submit方法,会向agent发送监控命令以及传递对应code的字节码。总的来说其实BTrace就是使用了java attach api附加agent.jar,然后使用脚本解析引擎+asm来重写指定类的字节码,再使用instrument实现对原有类的替换。

3 安装并启动btrace

1.     安装BTrace,下载tar.gz包,在服务器上解压即可运行。

2.     确认需要监控的java应用,获取进程PID。

3.     使用java语言写一个BTrace脚本,如Demo.java。

进入$BTRACE_HOME/bin目录 
    执行 ./btrace [目标进程的PID] Demo.java

4 btrace实例

首先我们编写一个简单的java程序作为被监控的对象:

import java.util.Random;  
  
public class HelloWorld {  
    public static void main(String[] args) throws Exception {  
        //CaseObject object = new CaseObject();  
        while (true) {  
            Random random = new Random();  
            execute(random.nextInt(4000));  
              
            //object.execute(random.nextInt(4000));  
        }        
    }  
    public static Integer execute(int sleepTime) {  
        try {  
            Thread.sleep(sleepTime);  
        } catch (Exception e) {  
        }  
        System.out.println("sleep time is=>"+sleepTime);  
        return 0;  
    }  
}

其次需要编写一个btrace脚本,如下所示:

import static com.sun.btrace.BTraceUtils.println;import static com.sun.btrace.BTraceUtils.str;import static com.sun.btrace.BTraceUtils.strcat;import static com.sun.btrace.BTraceUtils.timeMillis;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.TLS;@BTracepublic class TraceHelloWorld {
@TLS
private static long startTime = 0;
@OnMethod(clazz = "my.app.test.HelloWorld", method = "execute") public static void startMethod(){
startTime = timeMillis();
}
@OnMethod(clazz = "my.app.test.HelloWorld", method = "execute", location = @Location(Kind.RETURN)) public static void endMethod(){
println(strcat("the class method execute time=>", str(timeMillis()-startTime)));
println("-------------------------------------------");
}
@OnMethod(clazz = "my.app.test.HelloWorld", method = "execute", location = @Location(Kind.RETURN)) public static void traceExecute(@ProbeClassName String name,@ProbeMethodName String method,int sleepTime){
println(strcat("the class name=>", name));
println(strcat("the class method=>", method));
println(strcat("the class method params=>", str(sleepTime))); }
}
以下是需要注意的几个点:

1、@btrace这个annotation表明这个类是btrace脚本,

2、@OnMethod(clazz = "my.app.test.HelloWorld", method = "execute")

中clazz标明要监控那个类,也可以用正则匹配的方式,method标明要监控类的哪个方法

3、其中用到的几个方法timeMillis(),获取时间,println(str)输出

其中clazz=...  method=... 这两个属性,指定了这个BTrace方法的注入位置,这个注入的位置叫probe point, 具体来讲,excute()方法叫probed method, TraceHelloWorld类叫probed class。 也就是说, Btrace脚本中的方法endMethod()会注入在目标JVM的com.netease.qa.btrace.Demo1.add()调用处。注入操作是通过修改excute()方法的字节码实现的。

一旦注入成功,action method会在被监控应用执行到probe point的时候被触发执行。但是,这里具体是add()方法调用前,还是调用完成时呢? 这个由@Location注解指定,这里的value=Kind.RETURN,指定了endMethod方法会在调用结束后执行。

启动btrace脚本后,可以看到以下输出:

可以看到这样就完成了一个简单的btrace脚本的编写以及监控应用实践的工作。

免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击

相关文章:
【推荐】 Vue 依赖收集原理分析
【推荐】 3招搞定APP注册作弊

初识btrace的更多相关文章

  1. Android动画效果之初识Property Animation(属性动画)

    前言: 前面两篇介绍了Android的Tween Animation(补间动画) Android动画效果之Tween Animation(补间动画).Frame Animation(逐帧动画)Andr ...

  2. 初识Hadoop

    第一部分:              初识Hadoop 一.             谁说大象不能跳舞 业务数据越来越多,用关系型数据库来存储和处理数据越来越感觉吃力,一个查询或者一个导出,要执行很长 ...

  3. python学习笔记(基础四:模块初识、pyc和PyCodeObject是什么)

    一.模块初识(一) 模块,也叫库.库有标准库第三方库. 注意事项:文件名不能和导入的模块名相同 1. sys模块 import sys print(sys.path) #打印环境变量 print(sy ...

  4. 初识IOS,Label控件的应用。

    初识IOS,Label控件的应用. // // ViewController.m // Gua.test // // Created by 郭美男 on 16/5/31. // Copyright © ...

  5. UI篇(初识君面)

    我们的APP要想吸引用户,就要把UI(脸蛋)搞漂亮一点.毕竟好的外貌是增进人际关系的第一步,我们程序员看到一个APP时,第一眼就是看这个软件的功能,不去关心界面是否漂亮,看到好的程序会说"我 ...

  6. Python导出Excel为Lua/Json/Xml实例教程(一):初识Python

    Python导出Excel为Lua/Json/Xml实例教程(一):初识Python 相关链接: Python导出Excel为Lua/Json/Xml实例教程(一):初识Python Python导出 ...

  7. 初识SpringMvc

    初识SpringMvc springMvc简介:SpringMVC也叫Spring Web mvc,属于表现层的框架.Spring MVC是Spring框架的一部分,是在Spring3.0后发布的 s ...

  8. 初识redis数据类型

    初识redis数据类型 1.String(字符串) string是redis最基本的类型,一个key对应一个value. string类型是二进制安全的.意思是redis的string可以包含任何数据 ...

  9. Redis初识、设计思想与一些学习资源推荐

    一.Redis简介 1.什么是Redis Redis 是一个开源的使用ANSI C 语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的API.从2010 年 ...

随机推荐

  1. Chrome 前端 插件

    本文内容都来源于偶整理的fetool. 想让更多使用Chrome的小伙伴,体验到这些令人愉悦的小工具,所以单独整理了这篇文章. 如果你是 前端/服务端/设计/面向Github编程/视觉控,相信下列的插 ...

  2. asp识别手机端

    <script type="text/javascript"> var mobileAgent = new Array("iphone", &quo ...

  3. 使用UIWebView载入本地或远程server上的网页

    大家都知道,使用UIWebView载入本地或远程server上的网页,sdk提供了三个载入接口: - (void)loadRequest:(NSURLRequest *)request; - (voi ...

  4. 1185: [HNOI2007]最小矩形覆盖

    1185: [HNOI2007]最小矩形覆盖 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 1426  Solve ...

  5. 2015年度新增开源软件排名TOP 100,EasyDarwin开源流媒体服务器排名第17

    本榜单包含 2015 年开源中国新收录的 5977 款开源软件中,根据软件本身的关注度.活跃程度进行排名前 100 名的软件.从这份榜单中或许可以了解到最新业界的趋势. 榜单详情:http://www ...

  6. JQuery 如何获取select选中的值

    一.html代码 <select id="ddl"> <option value="100" emoney="12" &g ...

  7. extjs中新建窗体时,给窗体添加背景图片不显示问题之一

    1.在extjs中新建窗体时,给窗体添加背景图片不显示,例如下面的代码. 不显示的原因:因为设置了  layout: 'fit', Ext.create('Ext.Window', { title: ...

  8. go网关

    package main import ( "flag" "fmt" "io" "net" "os" ...

  9. a REST API

    https://spring.io/guides/tutorials/bookmarks/ http://roy.gbiv.com/untangled/2008/rest-apis-must-be-h ...

  10. Congruent Matrices

    http://mathworld.wolfram.com/CongruentMatrices.html Two square matrices  and  are called congruent i ...