
Debugging a Java application that cannot be stopped. Catching the exotic of execution with the most affordable means - BTrace approach
- Tutorial

Java applications - this means in the modern Java world the opportunity to meet such percentages by 90%, or even more (we consider the most common environments, HotSpot based JVM versions from 1.6)
that cannot be stopped - the application works, and it is absolutely impossible to restart it for one reason or another
exotic - something that way, it is not every day in the head vzbredet catch (defined sequence of method invocations, strange combinations of parameter values, ...)
means available - free of charge, it is efficient, effective, easy, simple and .d, etc. This article explores the great BTrace tool kenai.com/projects/btrace
And by itself, nothing has been specifically added to the Java application code in advance regarding debugging tools ...
This article is essentially a continuation of the post "Debugging a Java application when it does not wait at all - welcome to the InTrace approach" habrahabr.ru/post/219661 , in which It was shown how to wedge into an already running application and collect a fairly detailed execution trace. That is a very useful skill, but in real life, sometimes, there are times when incomprehensible behavior skips with a probability of 1 in 1,000, or even worse, and try to drop it, find it in tons of traces.
Therefore, we take for example a simple program (file excitement / Coin.java) and we will collect "exotic" on the fly.
package excitement;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Random;
public class Coin {
public void head() {
}
public void tail() {
}
public static void main(String... args) throws Exception {
System.out.println("Нажмите любой Enter для продолжения...");
new BufferedReader(new InputStreamReader(System.in)).readLine();
Random rand = new Random();
for (int count = 0; count < 1000; ++count) {
if (rand.nextInt(2) > 0) {
new Coin().head();
} else {
new Coin().tail();
}
}
System.out.println("Вот и всё!");
}
}
Compile
javac excitement/Coin.java
And run
javac excitement.Coin
Nowhere is it easier, right? )
For exotic, I will take the exciting question: “How many times in a row will the heads and tails drop out as much as possible, well, and also how many times will they just fall out?” Such a test is rand.nextInt (2). What are the forecasts? Bets are accepted ...
A very famous and, besides everything else, just an excellent BTrace tool kenai.com/projects/btrace , repeatedly mentioned on the Habre in comments, but unfortunately never before described in posts, will help to get an answer .
To start it, you should consider a couple of ways:
1) for command-line fans - a console utility downloaded from kenai.com/projects/btrace/downloads/directory/releases/release-1.2.4 (the latest available version)
and launched as
btrace TracingScript.java
where
PID is the process identifier (obtained, for example, via jps)
TracingScript.java is a tracing script, with which a closer acquaintance will be a little further
2) window lovers are invited to use the plugin in VisualVM visualvm.java.net/download.html . Why go to Tools-> Plugins-> Available Plugins click on BTrace Workbench and click on “Install”, carefully read the license (although who reads them), ok, so be it, without any hesitation we agree to this and the next windows for everything . And now, after a successful installation, in the context menu of the process of interest, a new item “Trace Application ...” appeared in VisualVM

BTrace does its work relying on the algorithm described in a very Java-like script (you can also use D-scripts). It’s very similar - since it’s kind of the most jarring Java, but still because BTrace does not change the execution of the traced program (I mean, it’s still trying not to modify its behavior, only to receive information about the execution as much as possible following the format “ read-only "), you have to forget about many things in Java (starting with creating new objects and ending with many more than that, see kenai.com/projects/btrace/pages/UserGuide BTrace Restrictions) and use the tools provided directly by BTrace.
And now the script (file TracingScript.java)
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace // скриптом выступает джава класс
public class TracingScript {
@Property // возможно смотреть значения "на лету" через MBean JMX (jconsole, VisualVM, ...)
private static long tailCount;
@Property(name="Total head count is") // другое имя для JMX
private static long headCount;
@Property
private static long maxHeadSequence = 1;
@Property
private static long maxTailSequence = 1;
@Property
private static long sequence = 1;
@Property
private static long prevId = -1;
@OnMethod(clazz = "excitement.Coin", // вклиниваемся в метод в пакете excitement класса Coin
method = "head", // c именем head
location = @Location(Kind.RETURN)) // при возврате из него
public static void onHead() {
++headCount;
sequence = prevId == 0 ? sequence + 1 : 1;
if (sequence > maxHeadSequence) maxHeadSequence = sequence;
prevId = 0;
}
@OnMethod(clazz = "excitement.Coin",
method = "tail",
location = @Location(Kind.RETURN))
public static void onTail() {
++tailCount;
sequence = prevId == 1 ? sequence + 1 : 1;
if (sequence > maxTailSequence) maxTailSequence = sequence;
prevId = 1;
}
@OnExit // вызывается при завершении программы
public static void onexit(int code) {
println(strcat("total heads:", str(headCount))); // из-за ограничения на создание объектов наблюдаются свои примочки по работе со строками
println(strcat("total tails:", str(tailCount)));
println(strcat("max tail sequence:", str(maxTailSequence)));
println(strcat("max head sequence:", str(maxHeadSequence)));
}
}
In the end, run this script, press “Enter” in the program waiting for a coin toss, and we get (like someone else, but it turned out like this):
total heads:531
total tails:469
max tail sequence:9
max head sequence:8
In general, the eagle and the tails happened 8 and 9 times in a row (although I have several launches happened 10-11 times). Those who wish are invited to independently verify how the result coincides with the results of the formulas of probability theory (so as not to drop into a complicated topic here regarding the methods of generating such simple random numbers).
To summarize:
BTrace is a pretty powerful tool that allows you to trace very, very wild execution features on the fly. In this article, only the tip of the iceberg of its chic capabilities is touched (if you wish, at least take it and write a book), the material is presented with the aim of teaching the very basics and as much as possible interest. Who is hooked, see more details here kenai.com/projects/btrace/pages/UserGuide , first of all, pay attention to the number of annotations and a long list of very, very vitally useful examples. But still do not forget - everything happens at your own peril and risk, for the transformation of Java classes used by BTrace to achieve the goal (wedging) can always play a cruel joke.
And finally, about coins (physics and only) - often a coin is not perfectly balanced (usually an eagle is a bit heavier than tails), so toss a coin and get 50/50 in real life will fail. Be vigilant, take the side of the coin directly with your mind.
May good luck come with you)
Thank you for your attention!