JavaアプリHotトレーサー「BTrace」
BTraceは起動中のJavaアプリケーションのトレース情報を取得できる便利なツール。
公式:
http://kenai.com/projects/btrace/
Developer's Guide:
http://kenai.com/projects/btrace/pages/DeveloperGuide
使い方
上記から入手したbin内にbtraceというシェルがある。(Windowsはbat)
> bin/btrace [PID] [トレース用のJavaソース]
PIDはjpsで取得。
実行ユーザはトレース対象のJavaプロセスの実行ユーザと同じ。
トレース用のJavaソースはコンパイル不要!
ソースの書き方
アノテーション
◇クラスに適用するアノテーション @BTrace クラスの前に定義 ◇メインメソッドに適用するアノテーション @OnMethod clazz:トレースしたいクラス名。正規表現の場合は/で囲む。 (例)clazz="/java\.io\..*/" method:トレースしたいメソッド名。正規表現の場合は/で囲む。 (例)clazz="/.*/" location:@Locationを指定 @Location value:トレースを適用するタイミング。メソッド呼び出し時はKind.CALL clazz:トレースを適用するクラス。 method:トレースを適用するメソッド。 (例)location=@Location(Kind.CALL, clazz="/.*/", method="/.*/") @OnTimer 指定されたミリ秒置きにトレース (例)@OnTimer(4000) ◇メインメソッドのパラメータに適用するアノテーション @Self トレースしているオブジェクト @probeClassName トレースしているクラス名 @probeMethodName トレースしているメソッド名 @TargetInstance トレースしているメソッド内で呼ばれているオブジェクト @TargetMethodOrField トレースしているメソッド内で呼ばれているオブジェクトのメソッド @アノテーションなし トレースしているメソッド内で呼ばれているオブジェクトのメソッドのパラメータが入るみたい
例
org.sampleパッケージで呼び出されているメソッドのトレース
package sample; import static com.sun.btrace.BTraceUtils.currentThread; import static com.sun.btrace.BTraceUtils.name; import static com.sun.btrace.BTraceUtils.println; import static com.sun.btrace.BTraceUtils.str; import static com.sun.btrace.BTraceUtils.timestamp; import com.sun.btrace.BTraceUtils.Strings; import com.sun.btrace.annotations.BTrace; import com.sun.btrace.annotations.Kind; import com.sun.btrace.annotations.Location; import com.sun.btrace.annotations.OnMethod; import com.sun.btrace.annotations.ProbeClassName; import com.sun.btrace.annotations.ProbeMethodName; import com.sun.btrace.annotations.Self; import com.sun.btrace.annotations.TargetInstance; import com.sun.btrace.annotations.TargetMethodOrField; @BTrace public class OnCall { @OnMethod( clazz="/org\\.sample\\..*/", method="/.*/", location=@Location(value=Kind.CALL, clazz="/.*/", method="/.*/") ) public static void m( @Self Object self, @ProbeClassName String probeClass, @ProbeMethodName String probeMethod, @TargetInstance Object instance, @TargetMethodOrField String method, String text) { String msg = ""; msg = Strings.concat(msg, timestamp("yyyy/MM/dd HH:mm:ss.SSS")); msg = Strings.concat(msg, " "); msg = Strings.concat(msg, name(currentThread())); msg = Strings.concat(msg, " ["); msg = Strings.concat(msg, str(self)); msg = Strings.concat(msg, "#"); msg = Strings.concat(msg, probeMethod); msg = Strings.concat(msg, " -> "); msg = Strings.concat(msg, str(instance)); msg = Strings.concat(msg, "#"); msg = Strings.concat(msg, method); msg = Strings.concat(msg, "(\""); msg = Strings.concat(msg, text); msg = Strings.concat(msg, "\")"); msg = Strings.concat(msg, "]"); println(msg); } }
org.sampleパッケージで実行されているメソッドのトレース
package sample; import static com.sun.btrace.BTraceUtils.currentThread; import static com.sun.btrace.BTraceUtils.name; import static com.sun.btrace.BTraceUtils.println; import static com.sun.btrace.BTraceUtils.str; import static com.sun.btrace.BTraceUtils.timestamp; import com.sun.btrace.BTraceUtils.Strings; import com.sun.btrace.annotations.BTrace; import com.sun.btrace.annotations.OnMethod; import com.sun.btrace.annotations.ProbeClassName; import com.sun.btrace.annotations.ProbeMethodName; import com.sun.btrace.annotations.Self; @BTrace public class OnMethods { @OnMethod( clazz="/org\\.sample\\..*/", method="/.*/" ) public static void m( @Self Object self, @ProbeClassName String probeClass, @ProbeMethodName String probeMethod ) { String msg = ""; msg = Strings.concat(msg, timestamp("yyyy/MM/dd HH:mm:ss.SSS")); msg = Strings.concat(msg, " "); msg = Strings.concat(msg, name(currentThread())); msg = Strings.concat(msg, " ["); msg = Strings.concat(msg, str(self)); msg = Strings.concat(msg, "#"); msg = Strings.concat(msg, probeMethod); msg = Strings.concat(msg, "]"); println(msg); } }
例外発生時にトレース
package sample; import com.sun.btrace.annotations.*; import static com.sun.btrace.BTraceUtils.*; @BTrace public class OnThrow { @TLS static Throwable currentException; @OnMethod( clazz="java.lang.Throwable", method="<init>" ) public static void onthrow(@Self Throwable self) { currentException = self; } @OnMethod( clazz="java.lang.Throwable", method="<init>" ) public static void onthrow1(@Self Throwable self, String s) { currentException = self; } @OnMethod( clazz="java.lang.Throwable", method="<init>" ) public static void onthrow1(@Self Throwable self, String s, Throwable cause) { currentException = self; } @OnMethod( clazz="java.lang.Throwable", method="<init>" ) public static void onthrow2(@Self Throwable self, Throwable cause) { currentException = self; } @OnMethod( clazz="java.lang.Throwable", method="<init>", location=@Location(Kind.RETURN) ) public static void onthrowreturn() { if (currentException != null) { Threads.jstack(currentException); println("====================="); currentException = null; } } }
スレッド生成時にトレース
package sample; import static com.sun.btrace.BTraceUtils.name; import static com.sun.btrace.BTraceUtils.println; import static com.sun.btrace.BTraceUtils.timestamp; import com.sun.btrace.BTraceUtils.Strings; import com.sun.btrace.annotations.BTrace; import com.sun.btrace.annotations.OnMethod; import com.sun.btrace.annotations.Self; @BTrace public class ThreadStart { @OnMethod( clazz="java.lang.Thread", method="start" ) public static void onnewThread(@Self Thread t) { // D.probe("jthreadstart", Threads.name(t)); String msg = ""; msg = Strings.concat(msg, timestamp("yyyy/MM/dd HH:mm:ss.SSS")); msg = Strings.concat(msg, " starting ["); msg = Strings.concat(msg, name(t)); msg = Strings.concat(msg, "]"); println(msg); } }
スレッドのスタックトレース
package sample; import static com.sun.btrace.BTraceUtils.exit; import static com.sun.btrace.BTraceUtils.Threads.deadlocks; import static com.sun.btrace.BTraceUtils.Threads.jstackAll; import com.sun.btrace.annotations.BTrace; @BTrace public class JStack { static { deadlocks(false); jstackAll(); exit(0); } }
ヒープダンプの取得
※出力先は指定できない。Javaのカレントディレクトリに出力される。
JavaのSystem.Propertiesの"user.dir"を参照。
package sample; import static com.sun.btrace.BTraceUtils.print; import static com.sun.btrace.BTraceUtils.println; import com.sun.btrace.BTraceUtils.Sys; import com.sun.btrace.annotations.BTrace; @BTrace public class HeapDump { static { String name; if (Sys.$length() == 3) { name = Sys.$(2); } else { name = "heap.bin"; } Sys.Memory.dumpHeap(name); print("heap dumped! > "); print(Sys.Env.property("user.dir")); print(Sys.Env.property("file.separator")); print("btrace"); print(Sys.$(0)); println(); Sys.exit(0); } }
デッドロックの検出
package sample; import com.sun.btrace.annotations.*; import static com.sun.btrace.BTraceUtils.Threads.*; @BTrace public class Deadlock { @OnTimer(4000) public static void print() { deadlocks(); } }
参考:
http://d.hatena.ne.jp/torutk/20100930/p1
https://blogs.oracle.com/okazaki/entry/%E3%83%AF%E3%82%AF%E3%83%AF%E3%82%AF%E6%8A%80%E8%A1%93_btrace
http://gihyo.jp/dev/clip/01/orangenews/vol48/0004