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

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

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. commons io上传文件

    习惯了是用框架后,上传功能MVC框架基本都提供了.如struts2,springmvc! 可是假设项目中没有使用框架.而是单纯的使用jsp或servlet作为action,这时我们就能够使用commo ...

  2. 问题 “cell 出栈 selectBox 已选的图标,被释放掉,再次进入屏幕时,没有了已选图标 ” 解决方案

    如何 去解决 列表里面的selectBox已选情况,在滑出屏幕后被清除的问题.      我来在这里 详细说明一下, 在cell里面写一个方法,去专门修复滑出后,又滑进来 图标被冲刷掉的cell. 在 ...

  3. (转) 实现wince datagrid 上下滑屏数据浏览

    开发 基于wince 手持设备数据库应用时 由于是触摸屏 当datagrid 数据过多 往往用户烦于去控制又窄又细的上下滚动条 尤其是高分辨率的屏上 (如魅族M8系统 720×480) 而且datag ...

  4. 原来浏览器原生支持JS Base64编码解码 outside of the Latin1 range

    原来浏览器原生支持JS Base64编码解码 « 张鑫旭-鑫空间-鑫生活 https://www.zhangxinxu.com/wordpress/2018/08/js-base64-atob-bto ...

  5. Embed image in a <button> element 微信小程序 客服按钮

    html - Embed image in a <button> element - Stack Overflow https://stackoverflow.com/questions/ ...

  6. NOIP考前感悟

    闭关这么久,后来突然后悔自己前几天和暑假的状态很頽 不然进步也还能多一点吧 还好提前发现了,最后也还是努力了一把 也算不枉费自己的选择吧 从初中开始学习OI,到头来也没有什么成果 但还好自己高一 也还 ...

  7. [SCOI2009] 最长距离

    题目描述 windy有一块矩形土地,被分为 NM 块 11 的小格子. 有的格子含有障碍物. 如果从格子A可以走到格子B,那么两个格子的距离就为两个格子中心的欧几里德距离. 如果从格子A不可以走到格子 ...

  8. 【R】R语言生成随机数

    1.概述 作为一种语言进行统计分析,R有一个随机数生成各种统计分布功能的综合性图书馆.R语言可以针对不同的分布,生成该分布下的随机数.其中,有许多常用的个分布可以直接调用.本文简单介绍生成常用分布随机 ...

  9. Codeforces Round #340 (Div. 2) E. XOR and Favorite Number —— 莫队算法

    题目链接:http://codeforces.com/problemset/problem/617/E E. XOR and Favorite Number time limit per test 4 ...

  10. Codeforces Round #383 (Div. 2) D. Arpa's weak amphitheater and Mehrdad's valuable Hoses —— DP(01背包)

    题目链接:http://codeforces.com/contest/742/problem/D D. Arpa's weak amphitheater and Mehrdad's valuable ...