Development Tool series (1): Btrace-Online Debug tool
Btrace
Btrace is used to debug a running system and does not pause the system during debugging. It is particularly suitable for tracking online problems. You can monitor the call of any method in a system in real time. you can know the parameters and returned values of these methods, and how long the method call takes.
Btrace does not need to be installed. You only need to download a package and decompress it.
Btrace is used as bin/btrace <pid> <trace-script>. Pid is a running java Process, and trace-script is a tracking script, which is actually a piece of java code.
Hello World
First, we simulate a running program, which has only one loop.
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) { } }}
Then open this program: java com. caipeichao. NullApp
Run the jps command to obtain the PID of the program. Here it is 13348.
> jps3034 RemoteMavenServer2902 Main15147 Jps13348 NullApp
Now that the preparation is complete, write the most important tracking script.
Import static com. sun. btrace. BTraceUtils. *; import com. sun. btrace. annotations. *; @ BTracepublic class HelloBtrace {// when com. caipeichao. nullApp. run the @ OnMethod (clazz = "com. caipeichao. nullApp ", method =" sleep ", location = @ Location (Kind. RETURN) public static void onSleep () {println ("Hello world ");}}
Run btrace to obtain the following output.
> btrace 13348 HelloBtrace.javaHello worldHello worldHello worldHello worldHello worldHello world
Common annotations
Name |
Scope |
Function |
@ BTrace |
Class |
Declare tracking script |
@ OnMethod (clazz, method, location) |
Method |
When the specified method is called |
@ OnMethod (method = "<init> ") |
Method |
When the constructor is called |
@ OnMethod (clazz = "/java \. io \ .. * Input /")) |
Method |
Method Name regular match |
@ Location (kind) |
@ OnMethod |
Before or after a monitoring method is called |
@ Location (value = Kind. NEWARRAY, clazz = "char ") |
@ OnMethod |
New monitoring Array |
@ Self |
Parameters |
Indicates the Monitored object |
@ ProbeMethodName |
Parameters |
Name of the monitored Method |
@ ProbeClassName |
Parameters |
Monitored Class Name |
@ OnTimer (interval) |
Method |
Call a method regularly |
@ OnLowMemory (pool, threshold) |
Method |
When the memory is insufficient |
@ OnExit |
Method |
When the program exits |
@ OnProbe (namespace = "java.net. socket", name = "bind ") |
Method |
Monitor the bind method in the socket |
Common Methods
Method |
Function |
Println |
Output a line in the local console |
Print |
Output in the local console |
PrintArray |
Output an array on the local console |
Jstack |
Print the call stack of the Remote Method |
JstackAll |
Output call stacks of all threads |
Exit |
Exit tracking script |
Strings. strcat |
Connection string |
Reflactive. name |
Get class name |
Threads. name |
Thread name |
Threads. currentThread |
Current thread |
Deadlocks |
Deadlocked threads |
Sizeof |
Obtain the object size. For example, if the List object is returned, List. size () is returned () |
Sys. Env. property |
Get System Variables |
Principle
BTrace uses the java. lang. instrument package for code injection. First, connect to the remote JVM through VirtualMachine. attach (pid), and then load a btrace jar package through VirtualMachine. loadAgent ("*. jar. The most important code for this jar package is as follows.
Public static void premain (String args, Instrumentation inst) {main (args, inst);} public static void agentmain (String args, Instrumentation inst) {main (args, inst );} // Add the btrace jar package to the ClassLoader search directory 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 () ;}// enable the private static void startServer (){... while (true) {try {... handleNewClient (client);} catch (RuntimeException re) {if (isDebug () debuuplint (re);} catch (IOException ioexp) {if (isDebug ()) debuuplint (ioexp) ;}}// modify the class definition in the memory private static void handleNewClient (final Client client ){... inst. addTransformer (client, true );... inst. retransformClasses (classes);} // use ASM to dynamically generate bytecode 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 );...}}
In a word, btrace uses the instrument tool to modify the class bytecode in JVM memory to inject code.