tags: java, troubleshooting, monitor,btrace
In a word, BTrace is a powerful Java online application detection tool (dynamic tracking tool). It can detect the running status of the code without modifying the application code, and then diagnose the problem under the premise of constantly applying the service. It is a necessary tool in production environment, and this article will explain its use.
1 the introduction
BTrace is an open source software. The github address is: The introduction of https://github.com/btraceio/btrace, a website is BTrace is a safe, dynamic tracing tool for the Java platform., It is a secure tool for dynamically tracing Java applications, that is, dynamically injecting tracing code into the bytecode of the target application. What is dynamic? As we all know, when a Java application is started, the class file is loaded into the JVM to run. At this point, the class code function is determined and static (cannot be changed), and the only way to change it is by modifying the code, recompiling, deploying, and starting.
And when it is applied in the processing line, we often need to look at the code to run, the parameter value, the return value view, or add their own need to debug log, etc., during the development phase, add log, restart the no problem, but have in the production environment (production environment is generally not easy closing services, and even can restart, can happen at the scene and destroys, Can’t reproduce the problem), is there a way to dynamically add what you want to monitor (track) while your Java application is running, without restarting the program? Btrace is one such dynamic tracking tool that allows you to monitor application performance without restarting it. You can retrieve runtime data such as method parameters, return values, global variables, and stack information. This article is to describe the operation principle and use of BTrace.
2 Operation principle of BTrace
2.1 Dynamic modification and replacement of class files
BTrace is implemented based on Java dynamic tracing technology. Java developers are familiar with the process of writing Java code, compiling it into a class file, and then loading the class into the JVM to run it. If you want to modify the class to add trace content, such as adding output to a method, without stopping the application, there are two main things:
- (1) The changes have been loaded to
JVM
Class to add custom output - (2) Replace classes running in the JVM
The first step is to modify the bytecode class file. Since the JVM runs class files, it is not possible to modify the bytecode class file directly (of course, bytecode files are not nearly as readable as Java code), but there is already a framework for doing this: ASM. It also provides interfaces that allow you to easily manipulate bytecode files, inject methods to modify classes, dynamically create a new class, and so on. Spring uses this technique to implement dynamic proxies.
The second step, replacement, if to replace it, you will need to use Java to provide Java. Lang. Instrument, Instrumentation, it has two interface redefineClasses and retransformClasses, RedefineClasses replaces the existing class file by providing the bytecode file itself, and retransformClasses replaces the existing bytecode file after modifying it. Note that the use of instrument is limited (you cannot add, modify, or delete existing fields and methods, change method signatures, or change inherited properties) :
The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance
Copy the code
2.2 Module and running process of BTrace
BTrace is based on the technology front, the article “the Java dynamic tracking technology to explore” (https://mp.weixin.qq.com/s/_hSaI5yMvPTWxvFgl-UItA) for dynamic tracking technology has carried on the detailed instructions, here is a brief note.
2.2.1 Main modules
-
BTrace scripts: With annotations defined by BTrace, we can easily develop scripts as needed.
-
Compiler: Compiles BTrace scripts into BTrace class files.
-
Client: sends a class file to the Agent.
-
Agent: Java-based Attach API. Agent can dynamically Attach to a running JVM, start a BTrace Server, and receive BTrace scripts from the client. Parse the script and find the class to modify based on the rules in the script; After modifying the bytecode, invoke the ReTransform interface of the Java Instrument to modify the object behavior and make the modification take effect.
2.2.2 Operation process
The operation flow chart is as follows:
Like Java source code, Btrace scripts (also Java files) are first written and compiled, which are sent to the Agent via the client. The Agent attaches the API to the JVM and starts the Agent server to receive the content sent by the Client. Then, ASM is used to modify the bytecode file. Then, Java Instrument’s ReTransform interface is used to replace the modified class file. After running, agent sends the output to client for display.
3 BTrace installation
Now that you know how BTrace works, you can install it and try it out. The example used in this article is again java-monitor-example. BTrace is easy to install out of the box.
- Download address (current latest version is
[v1.3.11.3]
) :https://github.com/btraceio/btrace/releases
- Decompress to the server where the Java application to be monitored resides
btrace
The command inbin
directory- If you want to execute in any directory, you need to change the
btrace
Set to environment variables (export
)
4 Application scenario of BTrace
Basically, BTrace is only useful for dynamically tracing the output of a class. You cannot add attributes, delete methods, modify inheritance, etc. This is consistent with the limitations of Instrument mentioned earlier. Generally speaking, Btrace is used for online application monitoring, which belongs to the log output category. Most of them include the following scenarios:
- View the input and return values of a method
- View the response time of a method
- Check whether a line of code has been executed
- Prints system parameters or JVM startup parameters
- Prints the thread stack for the method call
- Abnormal information is printed when an exception occurs
5 BTrace use
As a standalone tool, Btrace runs only locally by default, meaning that to monitor which Java application is running, you need to extract it to the appropriate server. In this example, we run java-monitor-Example as the Java application to monitor, and then write the script, run the script, and view the output according to the monitoring business requirements.
5.1 Script Writing
5.1.1 Notes and BTraceUtils
Btrace scripts are similar to Java code, but much simpler. They use annotations provided by Btrace and BTraceUtils to tell Btrace which classes to intercept, when to intercept, and where to intercept, and BTraceUtils to print out information. Examples given on the official website are as follows:
package samples;
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
/** * This script traces method entry into every method of * every class in javax.swing package! Think before using * this script -- this will slow down your app significantly!! * /
@BTrace public class AllMethods {
@OnMethod(
clazz="/javax\\.swing\\.. * /",
method="/. * /"
)
public static void m(@ProbeClassName String probeClass, @ProbeMethodName String probeMethod) {
print(Strings.strcat("entered ", probeClass));
println(Strings.strcat(".", probeMethod)); }}Copy the code
The above code, represented, intercepts all calls to methods that begin with Javax. swing and then prints out the class and method names. Notice that the annotations are @bTrace, @onMethod, @ProbeclassName, @ProbeMethodName, and print, println are static methods provided by BTraceUtils. BTraceUtils also provides a number of printing methods (which will be covered in a later example). Also, note that trace operations need to be specified in the body of a static method, so static methods are required.
In addition, about BTrace provide annotations, details you can refer to the official document (https://github.com/btraceio/btrace/wiki/BTrace-Annotations). Mainly include the following:
/**Class Annotations*/
@com.sun.btrace.annotations.DTrace
@com.sun.btrace.annotations.DTraceRef
@com.sun.btrace.annotations.BTrace
/**Method Annotations*/
@com.sun.btrace.annotations.OnMethod
@com.sun.btrace.annotations.OnTimer
@com.sun.btrace.annotations.OnError
@com.sun.btrace.annotations.OnExit
@com.sun.btrace.annotations.OnEvent
@com.sun.btrace.annotations.OnLowMemory
@com.sun.btrace.annotations.OnProbe
/**Argument Annotations*/
@com.sun.btrace.annotations.Self
@com.sun.btrace.annotations.Return
@com.sun.btrace.annotations.CalledInstance
@com.sun.btrace.annotations.CalledMethod
/**Field Annotations*/
@com.sun.btrace.annotations.Export
@com.sun.btrace.annotations.Property
@com.sun.btrace.annotations.TLS
Copy the code
Among them, @onMethod is widely used. It needs to be emphasized that it is mainly composed of three attributes clazz, Method and location.
-
Clazz: the full path name, such as me. Mason. The monitor. The controller. The UserController
-
Method: The name of the method to monitor, such as getUsers
-
Location: Intercept timing, using the @location annotation.
@location has the following types:
Kind.ENTRY
: called when the method is enteredKind.RETURN
The: method is called when it finishes executing, only if the interception position is defined asKind.RETURN
To get the result returned by the method@Return
And execution time@Duration
Kind.CALL
Called when other methods are called in the: methodKind.LINE
: By setting line, you can monitor whether the code executes to the specified locationKind.ERROR, Kind.THROW, Kind.CATCH
: Tracing of abnormal conditions
5.1.2 About the Compilation
It is recommended to use the Java Maven project development environment to write, you can use the code prompt function. Write it and then put it in the server that needs to be monitored. However, you need to reference the corresponding JAR packages (btrace-agent,btrace-boot,btrace-client) in the build directory of the downloaded installation. It can be used by importing pom.xml. As follows:
<! -- BTrace -->
<dependency>
<groupId>com.sun.btrace</groupId>
<artifactId>btrace-agent</artifactId>
<version>1.3.11.3</version>
<type>jar</type>
<scope>system</scope>
<systemPath>E: / btrace - bin - 1.3.11.3 / build/btrace - agent. The jar</systemPath>
</dependency>
<dependency>
<groupId>com.sun.btrace</groupId>
<artifactId>btrace-boot</artifactId>
<version>1.3.11.3</version>
<type>jar</type>
<scope>system</scope>
<systemPath>E: / btrace - bin - 1.3.11.3 / build/btrace - boot. The jar</systemPath>
</dependency>
<dependency>
<groupId>com.sun.btrace</groupId>
<artifactId>btrace-client</artifactId>
<version>1.3.11.3</version>
<type>jar</type>
<scope>system</scope>
<systemPath>E: / btrace - bin - 1.3.11.3 / build/btrace - client. The jar</systemPath>
</dependency>
Copy the code
5.2 Script Running
The following help information is displayed:
Btrace PID btracefile.java and then view the output (you can also print the content to a file for further view, such as btrace PID btracefile.java > info.txt). If a specific JAR package is used, the parameter cp or CLASspath needs to be added. The following example prints the return value of the called method:
5.3 Script Examples
The BTrace script is in the BTrace directory of the example project java-monitor-example. Java-monitor-example is a Controller and a Service, respectively. The following methods are used to dynamically trace.
/** * UserController.java **/
@GetMapping("/user")
public ResponseResult<User> getUser(a) {
User user = userService.getUser();
return ResponseResult.ok(user);
}
@GetMapping("/users")
public ResponseResult<User> getUsers(int num) {
List<User> users = userService.getUsers(num);
return ResponseResult.ok(users);
}
/** * userservice.java * get user ** by ID@return* /
public User getUser(a) {
return mockUser();
}
/** * get the user array **@return* /
public List<User> getUsers(int num) {
userList.clear();
for(int i=0 ; i < num; i++){
userList.add(mockUser());
}
return userList;
}
Copy the code
5.3.1 Printing method information
- Prints the arguments when the method is called (called
UserController
thegetUsers
Method print)
@OnMethod(clazz = "me.mason.monitor.controller.UserController"
,method = "getUsers",location = @Location(Kind.ENTRY))
public static void readFunction(@ProbeClassName String className, @ProbeMethodName String methodName, AnyType[] args) {
// Print time
BTraceUtils.println(BTraceUtils.Time.timestamp("yyyy-MM-dd HH:mm:ss"));
BTraceUtils.println("method controller");
BTraceUtils.printArray(args);
BTraceUtils.println(className + "," + methodName);
BTraceUtils.println("= = = = = = = = = = = = = = = = = = = = = = = = = =");
}
Copy the code
- Prints the return value when the method is called
@OnMethod(clazz = "me.mason.monitor.service.UserService"
,method = "getUsers",location = @Location(Kind.RETURN))
public static void printReturnData1(@Return AnyType result){
BTraceUtils.println(BTraceUtils.Time.timestamp("yyyy-MM-dd HH:mm:ss"));
BTraceUtils.printFields(result);
BTraceUtils.println("= = = = = = = = = = = = = = = = = = = = = = = = = =");
BTraceUtils.println(BTraceUtils.str(result));
BTraceUtils.println("= = = = = = = = = = = = = = = = = = = = = = = = = =");
}
Copy the code
- Number of rows executed (check if executed
UserService
39)
@OnMethod(clazz = "me.mason.monitor.service.UserService"
,method = "getUsers",location = @Location(value = Kind.LINE,line = 39))
public static void printLineData(@ProbeClassName String className, @ProbeMethodName String methodName,int line){
BTraceUtils.println(BTraceUtils.Time.timestamp("yyyy-MM-dd HH:mm:ss"));
BTraceUtils.println(className + "," + methodName + ","+line);
BTraceUtils.println("= = = = = = = = = = = = = = = = = = = = = = = = = =");
}
Copy the code
- Method execution time (
UserController
thegetUsers
How long the method takes)
@OnMethod(clazz = "me.mason.monitor.controller.UserController"
,method = "getUsers",location = @Location(Kind.RETURN))
public static void getUsersDuration(@Duration long duration){
BTraceUtils.println(BTraceUtils.Time.timestamp("yyyy-MM-dd HH:mm:ss"));
BTraceUtils.println("time(ns):" + duration);
BTraceUtils.println("time(ms):" + BTraceUtils.str(duration / 1000000));
BTraceUtils.println("time(s):" + BTraceUtils.str(duration / 1000000000));
BTraceUtils.println("= = = = = = = = = = = = = = = = = = = = = = = = = =");
}
Copy the code
5.3.2 Printing system properties and JVM properties
Similar to the JDK command line tool jinfo, in addition to jmap and jStatck can query official examples.
@BTrace
public class JInfo {
static {
println("System Properties:");
printProperties();
println("VM Flags:");
printVmArguments();
println("OS Enviroment:");
printEnv();
exit(0); }}Copy the code
5.3.3 Abnormal Output
Java developers should know that Java exceptions are divided into Error and Exception, and that they are both subclasses of Throwable, meaning that all exceptions in Java have Throwable as their parent, so just trace the constructor for this and print out the stack. As follows:
// Local variable storage exception
@TLS static Throwable currentException;
// The exception constructor starts
@OnMethod(
clazz="java.lang.Throwable",
method="<init>"
)
public static void onthrow(@Self Throwable self) {
currentException = self;
}
// End of exception constructor, output stack
@OnMethod(
clazz="java.lang.Throwable",
method="<init>",
location=@Location(Kind.RETURN)
)
public static void onthrowreturn(a) {
if(currentException ! =null) {
Threads.jstack(currentException);
println("= = = = = = = = = = = = = = = = = = = = =");
currentException = null; }}Copy the code
5.4 Script Restrictions
BTrace is “read only” to the JVM. What BTrace does is, although it changes the bytecode, it mainly outputs the required information and has no impact on the overall program. Note that since the class file is being replaced dynamically, the modified bytecode is not automatically restored. As noted in the official documentation, BTrace scripts have the following limitations:
-
Object creation is not allowed
-
Creating arrays is not allowed
-
Exceptions are not allowed
-
Catch exceptions are not allowed
-
Not allowed to call other object or class of methods, only allow you to call com. Sun. Btrace. BTraceUtils provided in the static method (some data processing and information output tools)
-
Class attributes are not allowed to change
-
Member variables and methods are not allowed, only static public void methods are allowed
-
Inner classes, nested classes are not allowed
-
Synchronization methods and blocks are not allowed
-
Loops are not allowed
-
No arbitrary inheritance of other classes (except, of course, java.lang.object)
-
Interface implementation is not allowed
-
Assert is not allowed
-
Class objects are not allowed
6 Some lessons
- Set up the use of Java maven project development environment for scripting, the introduction of the corresponding JAR, to provide code prompt function.
- Check out the official examples provided in the download package at:
Btrace - bin - 1.3.11.3 \ samples
directory BTrace
The input parameter traced in the script, the return value type is simple type used directly (such as int,float, etc.), complex type can be usedAnyType
, but if you are using a type in a custom package (such as User), you need to add it when you run the scriptcp
orclasspath
Parameter to specify the custom package.- General simple type or string, used directly
print
orprintln
, print object properties availableprintFields
To printList
, you can useBTraceUtils.println(BTraceUtils.str(list))
- Printing the separator on the last line of the probe method is strongly recommended. The output may have buffer delay. If the output is not delimited, the output may not be output or the output may not be delimited. Separation available
BTraceUtils.println
orBTraceUtils.println("============")
.
7 summary
Btrace is a powerful tool for using dynamic tracing technology, which is essential for Java applications that want to diagnose problems by logging out without stopping the service. This paper describes the operation principle, installation, application scenarios, script writing and operation of Btrace in detail, hoping to help you deepen your understanding of Btrace and solve online problems more conveniently and efficiently.
Parameter data
BTrace
Website:https://github.com/btraceio/btrace
BTrace
Comments:https://github.com/btraceio/btrace/wiki/BTrace-Annotations
- Example code address:
https://github.com/mianshenglee/my-example/tree/master/java-monitor-example
- Java dynamic tracking technology exploration:
https://mp.weixin.qq.com/s/_hSaI5yMvPTWxvFgl-UItA
- Brief analysis of BTrace Principle:
https://www.rowkey.me/blog/2016/09/20/btrace/
reading
- Java Application Monitoring (1)- Application monitoring techniques that Java programmers should know about
- Java Application Monitoring (2)- Secrets of Java commands
- Java Application Monitor (3)- Do you master these command line tools
- Java Application Monitoring (4)- Online problem detection routines
- Java Application Monitoring (5)- Visual monitoring tools
- Java Application Monitoring (6)- Third-party memory analysis tool MAT