BTrace: Java online troubleshooting tool, btrace troubleshooting
What is BTrace?
BTrace is a killer for checking and solving online problems. BTrace can obtain all information during program execution by writing scripts. Note that you do not need to restart the service. Yes, you do not need to restart the service. Write the script and run it directly without the code of the original program.
Principle
In general, BTrace is based on the dynamic bytecode Modification Technology (Hotswap) to track and replace runtime java programs. The general principle can be described using the following formula:Client (Java compile api + attach api) + Agent (script parsing engine + ASM + JDK6 Instumentation) + Socket
In fact, BTrace is to use java attach api to append agent. jar, and then use the script parsing engine + asm to overwrite the bytecode of the specified class, and then use instrument to replace the original class.
Installation and configuration
This installation and configuration is performed in Ubuntu 14.04. The latest version of BTrace is 1.3.9, and the code is hosted on [github. Step 1: Download the releases btrace-bin-1.3.9.tgz on github, which has no build directory for the zip version. Step 2, extract the btrace-bin-1.3.9.tgz to a directory, such/home/fengzheng/soft/btrace
In this step, you can actually use it. You only need to add the absolute path before the btrace command when executing the script. If you want to execute it in any directory, perform step 3, configure environment variables, which includeJAVA_HOME
AndBTRACE_HOME
For example, my configuration is as follows:
export JAVA_HOME=/home/fengzheng/soft/jdk1.8.0_111export JRE_HOME=${JAVA_HOME}/jreexport CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib export PATH=${JAVA_HOME}/bin:$PATHexport BTRACE_HOME=/home/fengzheng/soft/btraceexport PATH=$PATH:$BTRACE_HOME/bin
Then execute the commandsource /etc/profile
To make the environment variable take effect immediately. Run the following command in any directory:btrace
Command.
Simple Test Cases
The simplest btrace syntax is:btrace $pid script.java
So you need to knowJava
Program process id, and then write a test script.
1. Write a resident memoryJava
Program. Here an infinite loop is written, and a set of computing results are output every five seconds. The content is as follows:
Package kite. lab. utils;/*** NumberUtil *** @ author fengzheng * @ date */public class NumberUtil {public int sum () {int result = 0; for (int I = 0; I <100; I ++) {result + = I * I;} return result;} public static void main (String [] args) {while (true) {Thread. currentThread (). setName ("calculation"); NumberUtil util = new NumberUtil (); int result = util. sum (); System. out. println (result); try {Thread. sleep (5000);} catch (InterruptedException e ){}}}}
By the way, the process of compiling and running Java through the command line is as follows:
Compile:javac -d . NumberUtil.java
, Locate NumberUtil. the directory where java is located, and then execute this command line, it will be in the current directory (. generate the directory structure shown in the package name, kite/lab/utils/NumberUtil. class
Run:java kite.lab.utils.NumberUtil
You can.
2. After the above program is executed, it is availablejps
Command to view the pid (which account is generally used to start the program, and which account is used to execute jps, except for the root account), run the jps command to see the following results:
root@ubuntu:/home/fengzheng/codes/btrace# jps10906 Jps10860 NumberUtil
3. the java Process just executed is 10860.
4. Compile the btrace script. The script content is as follows:
package kite;import com.sun.btrace.annotations.*;import static com.sun.btrace.BTraceUtils.Strings.strcat;import static com.sun.btrace.BTraceUtils.jstack;import static com.sun.btrace.BTraceUtils.println;import static com.sun.btrace.BTraceUtils.str;/** * NumberUtilBTrace * * @author fengzheng * @date 2017/6/20 */@BTracepublic class NumberUtilBTrace { @OnMethod( clazz="kite.lab.utils.NumberUtil", method="sum", location=@Location(Kind.RETURN) ) public static void func(@Return int result) { println("trace: ======================="); println(strcat("result:", str(result))); jstack(); }}
This means that after the execution ends (location = @ Location (Kind. RETURN), the execution ends), the output result and stack information
5. Pre-Compilation: run the pre-compilation command to check the correctness of the script. The pre-compilation command is btracec, which is a javac-like command, btracec NumberUtilBTrace. java
6. Call the command line for execution. btrace 10860 NumberUtilBTrace. java (if you want to save it to a local file, you can use the redirection command btrace 10860 NumberUtilBTrace. java> mylog. log) to print the following information:
trace: =======================result:328350kite.lab.utils.NumberUtil.sum(NumberUtil.java:16)kite.lab.utils.NumberUtil.main(NumberUtil.java:27)
7. Press ctrl + c to display the exit prompt, and then press 1 to exit.
Use Cases
BTrace is a post-event tool. The post-event tool is launched in the service, but you can use BTrace when you find the following problems.
For example, which methods are too slow to execute, for example, monitoring the method whose execution time exceeds 1 s
Check which methods call System. gc () and call stack.
View method parameters or object attributes
Methods With exceptions
To better solve the problem, we 'd better cooperate with preparation and monitoring in advance. The preparation in advance is tracking the problem and log output in some methods that may cause problems, in-process monitoring is to use some real-time monitoring tools, such as Visual Vm and jmc tools with interfaces or command line tools provided by jdk, in addition, the Metrics tool such as Graphite is used in combination with the web interface.
Limits
To ensure that the trace statement is read-only and minimize the impact on the program to be detected, BTrace has some limitations on the trace script (for example, it cannot change the state in the trace code)
BTrace class cannot create a new class, create an array, throw an exception, and catch an exception,
Instance methods and static methods cannot be called (except for com. sun. btrace. BTraceUtils)
The target program and object cannot be assigned to the BTrace instance or static field.
External, internal, anonymous, and local classes cannot be defined
There cannot be synchronization blocks and Methods
There cannot be Loops
The interface cannot be implemented, and the class cannot be extended.
The assert statement cannot be used, and the class literal value cannot be used.
Define interception methods
@ OnMethod: clazz, method, and location can be specified. This makes up the timing (location decision) for monitoring a class/some classes (clazz decision) A method/some methods (method decision ).
How to locate
1. Precise Positioning
Directly locate a method under a class. The test example above is
2. Regular Expression Positioning
The regular expression is between two "/". For example, the following example monitors all the methods in the javax. swing package. Note that in the formal environment, the range is as small as possible, and performance will be affected if it is too large.
@OnMethod(clazz="/javax\\.swing\\..*/", method="/.*/")public static void swingMethods( @ProbeClassName String probeClass, @ProbeMethodName String probeMethod) { print("entered " + probeClass + "." + probeMethod);}
Inject @ ProbeClassName String probeClass, @ ProbeMethodName String probeMethod parameter into the definition of the Interception Function to tell the script the actually matched class and method name.
3. Locate by interface or inheritance class
For example, if you want to match an interface that inherits or implements com. kite. base or a base class, you only need to add the + sign before the class. For example
@ OnMethod (clazz = "+ com. kite. base", method = "doSome ")
4. Locate by Annotation
Add @ to the front, for example, @ OnMethod (clazz = "@ javax. jws. WebService", method = "@ javax. jws. WebMethod ")
Interception time
The interception time is determined by the location. Of course, multiple interception times can be added for the same location. That is, the interception can be performed when a method is entered, when a method is returned, or when an exception is thrown.
1. Kind. Entry and Kind. Return
Indicates the start and return of the function, respectively. If no location is written, the default value is Kind. entry. Only the parameter value can be obtained using Kind. entry. Kind is required to obtain the return value or execution time. return
2. Kind. Error, Kind. Throw and Kind. Catch
It indicates that the exception is throw, the exception is caught, and the exception is not captured. In the Parameter definition of the interception function, a Throwable parameter is injected, indicating the exception.
@ OnMethod (clazz = "com. kite. demo ", location = @ Location (value = Kind. LINE, line = 20) public static void onBind () {println ("executed to 20th rows ");}
@OnMethod(clazz = "java.net.ServerSocket", method = "bind", location =@Location(Kind.ERROR)) public static void onBind(Throwable exception, @Duration long duration){ }
3. Kind. Call and Kind. Line
Kind. Call indicates which methods are called by the monitored method, for example:
@OnMethod(clazz = "com.kite", method = "login", location = @Location(value = Kind.CALL, clazz = "/.*/", method = "/.*/", where = Where.AFTER)) public static void onBind(@Self Object self, @TargetInstance Object instance, @TargetMethodOrField String method, @Duration long duration){ println(strcat("self: ", str(self))); println(strcat("instance: ", str(instance))); println(strcat("method: ", str(method))); println(strcat("duration(ms): ", str(duration / 1000000))); }
@ Self indicates the class of the currently monitored function. If it is a static class, it is null. @ TargetInstance indicates the class of the method or attribute called in the function. If it is a static method, it is null, @ TargetMethodOrField indicates the method or attribute to be called. To obtain the execution time, set where to Where. AFTER
Whether the Kind. Line Monitoring class executes the set number of rows, for example:
@ OnMethod (clazz = "com. kite. demo ", location = @ Location (value = Kind. LINE, line = 20) public static void onBind () {println ("executed to 20th rows ");}
Several examples to see who called GC
@OnMethod(clazz = "java.lang.System", method = "gc") public static void onSystemGC() { println("entered System.gc()"); jstack(); }
Print a method that takes more than Ms
@ OnMethod (clazz = "/com \\. kite \\. controller \\.. */", method = "/. */", location = @ Location (Kind. RETURN) public static void slowQuery (@ ProbeClassName String pcn, @ ProbeMethodName String probeMethod, @ Duration long duration) {if (duration> 1000000*100) {println (strcat ("class: ", pcn); println (strcat (" method: ", probeMethod); println (strcat (" duration: ", str (duration/1000000 )));}}
BTrace provides a series of samples, which can be viewed on github.
Notes
IfUnable to open socket file: target process not responding or HotSpot VM not loaded
The possible cause is that the user executing the BTrace script is different from the user running the Java Process.ps -aux | grep $pid
Check the execution user of the Java process to ensure that it is the same as the execution user of the BTrace script.
Ancient kite [public number] gushidefengzheng