初识btrace
此文已由作者易国强授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
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的更多相关文章
- Android动画效果之初识Property Animation(属性动画)
前言: 前面两篇介绍了Android的Tween Animation(补间动画) Android动画效果之Tween Animation(补间动画).Frame Animation(逐帧动画)Andr ...
- 初识Hadoop
第一部分: 初识Hadoop 一. 谁说大象不能跳舞 业务数据越来越多,用关系型数据库来存储和处理数据越来越感觉吃力,一个查询或者一个导出,要执行很长 ...
- python学习笔记(基础四:模块初识、pyc和PyCodeObject是什么)
一.模块初识(一) 模块,也叫库.库有标准库第三方库. 注意事项:文件名不能和导入的模块名相同 1. sys模块 import sys print(sys.path) #打印环境变量 print(sy ...
- 初识IOS,Label控件的应用。
初识IOS,Label控件的应用. // // ViewController.m // Gua.test // // Created by 郭美男 on 16/5/31. // Copyright © ...
- UI篇(初识君面)
我们的APP要想吸引用户,就要把UI(脸蛋)搞漂亮一点.毕竟好的外貌是增进人际关系的第一步,我们程序员看到一个APP时,第一眼就是看这个软件的功能,不去关心界面是否漂亮,看到好的程序会说"我 ...
- Python导出Excel为Lua/Json/Xml实例教程(一):初识Python
Python导出Excel为Lua/Json/Xml实例教程(一):初识Python 相关链接: Python导出Excel为Lua/Json/Xml实例教程(一):初识Python Python导出 ...
- 初识SpringMvc
初识SpringMvc springMvc简介:SpringMVC也叫Spring Web mvc,属于表现层的框架.Spring MVC是Spring框架的一部分,是在Spring3.0后发布的 s ...
- 初识redis数据类型
初识redis数据类型 1.String(字符串) string是redis最基本的类型,一个key对应一个value. string类型是二进制安全的.意思是redis的string可以包含任何数据 ...
- Redis初识、设计思想与一些学习资源推荐
一.Redis简介 1.什么是Redis Redis 是一个开源的使用ANSI C 语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的API.从2010 年 ...
随机推荐
- java 对账关键点
原理:双方交易信息对比是否平账 注意:对账bean必须重写 equals 方法 如图: //对账方法
- Scrapy爬虫入门系列2 示例教程
本来想爬下http://www.alexa.com/topsites/countries/CN 总排名的,但是收费了 只爬了50条数据: response.xpath('//div[@class=&q ...
- android:PopupWindow的使用场景和注意事项
1.PopupWindow的特点 借用Google官方的说法: "A popup window that can be used to display an arbitrary view. ...
- iOS8的UIPresentationController
本文转载至 http://kyfxbl.iteye.com/blog/2147888 从iOS8开始,controller之间的跳转特效,需要用新的API UIPresentationControll ...
- 同一世界服务器架构--Erlang游戏服务器
Erlang最大的优点是方便,很多基础功能都已经集成到Erlang语言中.之前用C++写服务器的时候,管理TCP连接很繁琐,需要写一大堆代码来实现.底层的框架需要写很多代码实现,这样既浪费时间 ...
- GCJ Qualification Round 2016 B题
经典的翻饼问题,直接做:从下往上看,已翻好的饼忽略掉:从上往下,连续的已翻好的一起翻过来:整个翻过来. /* * Author : ben */ #include <cstdio> #in ...
- Hackerspace
Hackerspace Software - HackerspaceWiki https://wiki.hackerspaces.org/Hackerspace_Software Hackerspac ...
- go echo studygolang ___go_build_myT_go__1_.exe
https://github.com/studygolang/studygolang [stat]; 用户在线数据存到哪里:redis -> 表示存入 redis,这样支持多机部署; onlin ...
- 解析json的方式
一.Javascrip操作json 原始方式: var str1 = '{ "name": "jacun", "addr": "b ...
- react-native填坑--react-navigation
Navigator已经被React Native废弃了.也许你可以在另外的一个依赖库里react-native-deprecated-custom-components里找到.不过既然官方推荐的是re ...