本文首发于个人微信公众号《andyqian》,期待你的关注!

前言

在《说说Java单元测试》文章中,强调了单元测试的重要性,也提倡大家一定要写单元测试,能帮我们筛选掉很多低级错误,找出一些没必要的bug,避免生产事故。单元测试通过后,我们开始集成,随着服务集成的日渐增多,业务逻辑也变得越来越复杂,在这样的前提下,解决bug就变得异常复杂。在本地环境中,我们可以通过日志分析 + debug的方式,进行排查解决,再不济,我们还可以开启远程调试进行解决。但当生产系统上出现了bug时,我们可不能开启远程调试,这样会造成线程阻塞,足以让生产系统爆炸的。那么,我们该怎么办呢?代码执行到哪一行了?我们两眼一抹黑,不知从何下手,真是一个悲伤的故事。当然了,我们也可以通过修改代码的方式新增日志,打印方法的入参,出参,上线,重启 ... 直至问题得以解决。办法虽然原始,好在能解决问题,但其过程非常痛苦,让人精疲力尽,有很多朋友估计都有过这样的经历。现在回过头来想,如果有这么一个工具,在不修改代码,不重启应用,不上线的前提下,就能查看到代码执行到哪一行,查看某个方法的出参,入参,查看方法的耗时,是该有多好。今天要介绍的就是这么一个工具 - BTrace ( Github主页:https://github.com/btraceio/btrace)

简介

BTrace 是一个安全,动态的Java追踪工具。通过动态(字节码),动态替换的原理以追踪正在运行的Java程序。简单的说,我们可以使用它在不修改代码,不重启应用,不上线的前提下,查看指定方法的运行环境,如:方法出入参,运行环境,方法耗时等运行时环境。正因为 BTrace 是动态追踪,尽量避免影响线上服务的可用性,在编写BTrace 脚本时,也有如下约定:

  1. 不能创建对象,数组。
  2. 不能throw,catch 异常。
  3. 不能有循环(for,while,do..while)。
  4. 不能实现接口。
  5. 不能有同步块及同步方法。
  6. 不能有断言语句。
  7. 不能有外部,内部,嵌套 或本地类。
  8. 不能进行任何实例好或静态方法调用,只能从com.sun.btrace.BtraceUtils类的公共静态方法。 ....

别看限制这么多,其实我们可操作的比这更多,其使用语法也非常简单,如下所示:

btrace <pid> <btrace-script>

其中 pid 是 需要追踪的 Java 进程 ID (可以通过 jps 命令查看) ,btrace-script 脚本是我们需要编写的追踪文件,语法会在下面详细介绍。

环境配置

1. 执行btrace环境

在使用之前,我们需要下载并安装,像设置JDK环境一样,设置Btrace环境即可。

以Linux为例:

  1. 下载 btrace:
wget https://github.com/btraceio/btrace/releases/download/v1.3.11.3/btrace-bin-1.3.11.3.tgz
  1. 设置环境,编辑 /etc/profile文件,向其添加如下内容,(其中 /usr/local/btrace/为 btrace 的安装路径)。
export BTRACE_HOME=/usr/local/btrace/;
export PATH=$PATH:$BTRACE_HOME;
  1. 使环境变量生效。
source /etc/profile;
  1. 设置完成后,可以使用btrace --version 命令验证其有效性。

2. BTrace 脚本编写环境

比较遗憾的是在 mvnrepository 仓库中,btrace是非常老的版本,通常建议通过Github下载其最新jar包上传至私服中使用,也可以引用本地进行使用,如下所示:

  1. 在 pom.xml 文件中的 properties 标签中,添加如下内容:
<btrace.home>/java/jar/btrace</btrace.home>

其中 /java/jar/btrace/为 btrace的本地路径,可修改为实际路径。

  1. 在 dependencies 标签下,添加如下依赖:
<!--btrace start--><dependency><groupId>com.sun.tools.btrace</groupId><artifactId>btrace-agent</artifactId><version>1.3.11.3</version><scope>system</scope><systemPath>${btrace.home}/build/btrace-agent.jar</systemPath></dependency><dependency><groupId>com.sun.tools.btrace</groupId><artifactId>btrace-boot</artifactId><version>1.3.11.3</version><scope>system</scope><systemPath>${btrace.home}/build/btrace-boot.jar</systemPath></dependency><dependency><groupId>com.sun.tools.btrace</groupId><artifactId>btrace-client</artifactId><version>1.3.11.3</version><scope>system</scope><systemPath>${btrace.home}/build/btrace-client.jar</systemPath></dependency><!--btrace end-->

也可以通过Maven plugin 插件的形式运行,这里不再演示,有兴趣的可以在其Github主页上查看方法。

编写 BTrace脚本

通过上面的一顿操作,是时候表演真正的技术了,下面以运行一段程序为例:

@POST@Path("/load")@Overridepublic UserDTO loadUserInfo() {return getUserInfo("www.andyqian.com","andyqian","andyqian");}/*** 获取用户信息* @param blog             博客地址* @param name             andyqian* @param officialAccount  公众号* @return user DTO*/private UserDTO getUserInfo(String blog,String name,String officialAccount){UserDTO userDTO = new UserDTO();userDTO.setBlog(blog);userDTO.setName(name);userDTO.setOfficialAccount(officialAccount);// 该段代码纯粹用于增加方法耗时, 无其他任何意义。try {Thread.sleep(1000);}catch (InterruptedException te){te.printStackTrace();}return userDTO;}

BTrace 脚本文件:

@BTrace
public class BtraceTest {/*** 打印用户信息*/@OnMethod(clazz="com.jq.wechat.facade.srv.impl.AuthRestServiceImpl", method="getUserInfo",location=@Location(value=Kind.RETURN))public static void printUserInfo(@Duration long duration,String blog, String name, String officialAccount){//BTraceUtils.print("====method duration: "+duration/1000000+" 毫秒=== ");BTraceUtils.println("blog:"+blog+" name:"+name+" account: "+ officialAccount);//1. 建议最后一行加上这个,(因为在测试过程中,最后一行未能显示)BTraceUtils.println();}
}

执行脚本结果后,我们请求接口多次,其脚本追踪结果如下:

andy@andyqian:/java/andyqian/wechat$ btrace 18596 BtraceTest.java
====method duration: 1000 毫秒=== blog:www.andyqian.com name:andyqian account: andyqian
====method duration: 1000 毫秒=== blog:www.andyqian.com name:andyqian account: andyqian
====method duration: 1000 毫秒=== blog:www.andyqian.com name:andyqian account: andyqian

备注:其中 18596 是我系统演示时的Java进程ID。你使用时,请使用 jps -l命令查看自己的进程ID。

当参数是对象,我们可以使 BTraceUtils.printFields()方法打印对象属性,也可以使用BTraceUtils.getInt(Field field, Object obj)打印对象中的指定Int类型属性。


写到这里,篇幅不知不觉已经很长了,上面介绍了BTrace的最基本用法,其实BTrace还是有很多用法值得我们掌握的,我们放在下一篇来介绍。


相关阅读:

《你该了解的Java注释》

《说说单元测试》

《一个Java细节》

《初探JDK源码之字符集》

扫码关注,一起进步

个人博客: http://www.andyqian.com

Java 生产神器 BTrace相关推荐

  1. java btrace_再谈Java 生产神器 BTrace

    本文首发于个人公众号<andyqian>,期待你的关注- 前言 在上一篇文章<Java 生产神器 BTrace>中我们认识了BTrace,并了解到 BTrace 脚本如何编写, ...

  2. java七武器系列_Java七武器系列孔雀翎-- 问题诊断神器BTrace

    古龙的小说对于大部分来说都不陌生,其中七武器系列中各个神器的名称更是在许多场合中被借用. 本次打算写一系列Java应用的分析诊断工具,也来借用下古龙的这些神器,来说明这些工作中使用起来事半功倍的分析诊 ...

  3. 利用神器BTrace 追踪线上 Spring Boot应用运行时信息

    可用于追踪线上 Java服务 运行时信息的神器 BTrace,你们经常用吗 ? 概述 生产环境中的服务可能会出现各种问题,但总不能让服务下线来专门排查错误,这时候最好有一些手段来获取程序运行时信息,比 ...

  4. 性能工具之Java分析工具BTrace入门

    文章目录 一.引言 二.BTrace是什么? 三.BTrace原理 四.安装配置 五.注意事项 六.使用示例 1.拦截一个普通方法 2.拦截构造函数 3.拦截同名函数,以参数区分 4.拦截方法返回值 ...

  5. Java生产环境下性能监控与调优详解 大纲 学习感悟

    Java生产环境下性能监控与调优详解 生产环境发生了内存溢出如何处理? 生产环境应该给服务器分配多少内存合适? 如何对垃圾收集器的性能进行调优? 4.生产环境CPU负载飙高该如何处理? 5.生产环境应 ...

  6. Java开发神器Lombok的使用与原理

    在面向对象编程中必不可少需要在代码中定义对象模型,而在基于Java的业务平台开发实践中尤其如此.相信大家在平时开发中也深有感触,本来是没有多少代码开发量的,但是因为定义的业务模型对象比较多,而需要重复 ...

  7. java生产问题快速定位_生产环境如何快速跟踪、分析、定位问题-Java

    我相信做技术的都会遇到过这样的问题,生产环境服务遇到宕机的情况下如何去分析问题?比如说JVM内存爆掉.CPU持续高位运行.线程被夯住或线程deadlocks,面对这样的问题,如何在生产环境第一时间跟踪 ...

  8. 都2020年了,这5个java IDE神器你还不知道?

    TIOBE的4月份编程语言排行榜出来了,java还是稳坐第一位,java最新的版本也到了13,一直以来java凭借其企业级应用的优势和大量的框架级应用俘获了大量的粉丝和企业客户. 谈到开发者,java ...

  9. Java多线程神器:join使用及原理

    转载自 Java多线程神器:join使用及原理 join() join()是线程类 Thread的方法,官方的说明是: Waits for this thread to die. 等待这个线程结束,也 ...

最新文章

  1. 网络基础知识总结_交换机
  2. API接口设计 注意问题
  3. Spring Boot中Thymeleaf的初步使用
  4. 卷影副本--给你后悔的机会,文件误删除,误更改,能够找到以前的版本。
  5. C/C++中指针和引用之相关问题研究
  6. 深入入门正则表达式(java) - 1 - 入门基础
  7. 手机文件上传服务器,如何上传文件到服务器 上传文件到服务器方法
  8. 没有用递归,写了一个文本转成树的小程序,代码凑和看吧
  9. 1010 - 线性dp - 除虫药水
  10. 微信小程序微信原生小程序如何通过后端返回的二进制流导出excel文件并保存和转发
  11. S型速度曲线_博图+变频器+三相异步电机(以堆垛机控制系统举例)
  12. python: npy数据写入excel文件
  13. 地区数据erea.js
  14. MATLAB怎么计算曲面面积,Matlab曲面面积估计.doc
  15. 激光测距项目整体框图及原理
  16. 【转载】Android提醒微技巧,你真的了解Dialog、Toast和Snackbar吗?
  17. EndNote20 快速入门
  18. opencv利用投影法进行水平切割和垂直切割
  19. 使用mdadm创建RAID
  20. 笨办法学python第五版_笨办法学Python(五)

热门文章

  1. WITH RECURSIVE and MySQL
  2. 309、各品牌路由器登录网址大全 路由器默认用户名/密码
  3. ICP算法实现(MATLAB)
  4. 解决Android平台移植ffmpeg的一揽子问题
  5. Java实现长度可变数组
  6. 【Git学习】git常用命令
  7. c语言程序设计 实践教学内容,C语言程序设计课程实验教学大纲.doc
  8. LoRa/LoRaWAAN技术
  9. 虚拟机网络、联网设置、与宿主机互联、网络配置
  10. Hello,World!向世界问好