开发工具系列(一):Btrace——线上Debug工具
2017-06-01 17:29
447 查看
原文地址:http://blog.csdn.net/caipeichao2/article/details/42109429
Btrace不需要安装,只要下载一个包,解压即可。
Btrace用法为
package com.caipeichao; public class NullApp { public static void main(String[] argv) { new NullApp().run(); } public void run() { for (int i = 0; i < 100000; i++) { sleep(1000); new MyObj().life(i); } } private static class MyObj { public void life(int n) { System.out.println(n); } } private void sleep(int n) { try { Thread.sleep(n); } catch (InterruptedException e) { } }}
然后开启这个程序:
通过jps命令得到这个程序的PID,这里为13348。
> jps3034 RemoteMavenServer2902 Main15147 Jps13348 NullApp
准备工作做完了,现在编写最重要的跟踪脚本。
import static com.sun.btrace.BTraceUtils.*;import com.sun.btrace.annotations.*; @BTracepublic class HelloBtrace { // 当com.caipeichao.NullApp.sleep方法返回时,执行该方法 @OnMethod(clazz="com.caipeichao.NullApp", method="sleep", location=@Location(Kind.RETURN)) public static void onSleep() { println("Hello world"); }}
运行btrace,得到如下输出。
> btrace 13348 HelloBtrace.javaHello worldHello worldHello worldHello worldHello worldHello world
public static void premain(String args, Instrumentation inst) { main(args, inst);} public static void agentmain(String args, Instrumentation inst) { main(args, inst);} // 将btrace的jar包添加到ClassLoader搜索目录 private static synchronized void main(final String args, final Instrumentation inst) { ... inst.appendToBootstrapClassLoaderSearch(new JarFile(new File(path))); ... inst.appendToSystemClassLoaderSearch(new JarFile(new File(path))); ... startServer();} // 开启服务 private static void startServer() { ... while (true) { try { ... handleNewClient(client); } catch (RuntimeException re) { if (isDebug()) debugPrint(re); } catch (IOException ioexp) { if (isDebug()) debugPrint(ioexp); } }} // 修改内存中的类定义 private static void handleNewClient(final Client client) { ... inst.addTransformer(client, true); ... inst.retransformClasses(classes);} // 用ASM动态生成字节码 abstract class Client implements ClassFileTransformer, CommandListener { static { ClassFilter.class.getClass(); ClassReader.class.getClass(); ClassWriter.class.getClass(); ... } private byte[] instrument(Class clazz, String cname, byte[] target) { byte[] instrumentedCode; try { ClassWriter writer = InstrumentUtils.newClassWriter(target); ClassReader reader = new ClassReader(target); Instrumentor i = new Instrumentor(clazz, className, btraceCode, onMethods, writer); ... }}
一句话总结,btrace利用instrument工具修改JVM内存中的类字节码,达到注入代码的目的。
Btrace
Btrace用于调试正在运行的系统,并且在调试时不会暂停系统。特别适用于跟踪线上问题。你可以实时监控一个系统中任何一个方法的调用,你可以知道这些方法的参数、返回值是什么,还可以知道方法调用消耗了多少时间。Btrace不需要安装,只要下载一个包,解压即可。
Btrace用法为
bin/btrace <pid> <trace-script>。其中
pid是正在运行的Java进程,
trace-script是跟踪脚本,它其实就是一段java代码。
Hello World
首先我们模拟一个正在运行的程序,它仅有一个循环。package com.caipeichao; public class NullApp { public static void main(String[] argv) { new NullApp().run(); } public void run() { for (int i = 0; i < 100000; i++) { sleep(1000); new MyObj().life(i); } } private static class MyObj { public void life(int n) { System.out.println(n); } } private void sleep(int n) { try { Thread.sleep(n); } catch (InterruptedException e) { } }}
然后开启这个程序:
Java com.caipeichao.NullApp
通过jps命令得到这个程序的PID,这里为13348。
> jps3034 RemoteMavenServer2902 Main15147 Jps13348 NullApp
准备工作做完了,现在编写最重要的跟踪脚本。
import static com.sun.btrace.BTraceUtils.*;import com.sun.btrace.annotations.*; @BTracepublic class HelloBtrace { // 当com.caipeichao.NullApp.sleep方法返回时,执行该方法 @OnMethod(clazz="com.caipeichao.NullApp", method="sleep", location=@Location(Kind.RETURN)) public static void onSleep() { println("Hello world"); }}
运行btrace,得到如下输出。
> btrace 13348 HelloBtrace.javaHello worldHello worldHello worldHello worldHello worldHello world
常用注解
名称 | 作用域 | 作用 |
---|---|---|
@BTrace | 类 | 声明跟踪脚本 |
@OnMethod(clazz,method,location) | 方法 | 当指定方法被调用时 |
@OnMethod(method="<init>") | 方法 | 当构造函数被调用时 |
@OnMethod(clazz="/java\\.io\\..*Input/")) | 方法 | 方法名称正则匹配 |
@Location(kind) | @OnMethod | 指定监控方法调用前还是调用后 |
@Location(value=Kind.NEWARRAY, clazz="char") | @OnMethod | 监控新增数组 |
@Self | 参数 | 表示被监控的对象 |
@ProbeMethodName | 参数 | 被监控的方法名称 |
@ProbeClassName | 参数 | 被监控的类名 |
@OnTimer(interval) | 方法 | 定时调用某个方法 |
@OnLowMemory(pool,threshold) | 方法 | 当内存不足时 |
@OnExit | 方法 | 当程序退出时 |
@OnProbe(namespace="java.net.socket",name="bind") | 方法 | 监控socket中的bind方法 |
常用方法
方法 | 作用 |
---|---|
println | 在本地控制台输出一行 |
在本地控制台输出 | |
printArray | 在本地控制台输出数组 |
jstack | 打印远程方法的调用调用栈 |
jstackAll | 输出所有线程的调用栈 |
exit | 退出跟踪脚本 |
Strings.strcat | 连接字符串 |
Reflactive.name | 获取类名 |
Threads.name | 线程名 |
Threads.currentThread | 当前线程 |
deadlocks | 打出死锁线程 |
sizeof | 获取对象的大小,比如List对象就返回 List.size() |
Sys.Env.property | 获取系统变量 |
原理
BTrace利用了java.lang.instrument包实现代码注入。首先通过
VirtualMachine.attach(pid)连接远程JVM,然后通过
VirtualMachine.loadAgent("*.jar")加载一个btrace的jar包。这个jar包最重要的代码如下。
public static void premain(String args, Instrumentation inst) { main(args, inst);} public static void agentmain(String args, Instrumentation inst) { main(args, inst);} // 将btrace的jar包添加到ClassLoader搜索目录 private static synchronized void main(final String args, final Instrumentation inst) { ... inst.appendToBootstrapClassLoaderSearch(new JarFile(new File(path))); ... inst.appendToSystemClassLoaderSearch(new JarFile(new File(path))); ... startServer();} // 开启服务 private static void startServer() { ... while (true) { try { ... handleNewClient(client); } catch (RuntimeException re) { if (isDebug()) debugPrint(re); } catch (IOException ioexp) { if (isDebug()) debugPrint(ioexp); } }} // 修改内存中的类定义 private static void handleNewClient(final Client client) { ... inst.addTransformer(client, true); ... inst.retransformClasses(classes);} // 用ASM动态生成字节码 abstract class Client implements ClassFileTransformer, CommandListener { static { ClassFilter.class.getClass(); ClassReader.class.getClass(); ClassWriter.class.getClass(); ... } private byte[] instrument(Class clazz, String cname, byte[] target) { byte[] instrumentedCode; try { ClassWriter writer = InstrumentUtils.newClassWriter(target); ClassReader reader = new ClassReader(target); Instrumentor i = new Instrumentor(clazz, className, btraceCode, onMethods, writer); ... }}
一句话总结,btrace利用instrument工具修改JVM内存中的类字节码,达到注入代码的目的。
相关文章推荐
- 开发工具系列(一):Btrace——线上Debug工具
- Intel系列开发工具- C++ Compiler,Fortran Compiler,IPP,MKL,VTune,Thread Checker
- .NET开发系列工具之NDoc:让NDoc支持简体中文!(含修改了的源代码)
- 使用VS进行工作流开发系列博客7-Developing Workflows in VS: Part6 - Deploy and Debug your workflow
- Intel软件开发工具及并行编程系列视频的收看指南(2)
- 初试Microsoft Expression 系列开发工具
- 《Moblin非官方教程》系列连载 第二章--第四节--Moblin项目提供的开发工具
- TMS320系列DSP开发工具CCS3.1的配置过程
- web 开发 debug 工具
- ArcGIS Server 开发系列(五)--自定义 Toolbar 工具
- [导入]Visual Studio 2005 Team Edition软件架构系列课程(4):模型驱动开发的领域特定语言(Domain Specific Language )工具
- ArcGIS Server 开发系列(五)--自定义 Toolbar 工具 (转载于Flyingis)
- ArcGIS Server 开发系列(五)--自定义 Toolbar 工具
- BlogEngine.Net架构与源代码分析系列part10:开发扩展(中)——Widget小工具
- DotNet开发工具系列之一Nunit
- [J2ME] JAVA 2 Micro Edition 系列专题 - 开发工具篇
- ArcGIS Server 开发系列(五)--自定义 Toolbar 工具 (转载于Flyingis)
- Intel软件开发工具系列课程(1):并行编程简介 推荐
- Intel软件开发工具及并行编程系列视频的收看指南(1)
- JavaWebStudio系列开发工具Visaul Struts版本简介