ksino's diary

覚えたことを忘れないように、小さなことでも書いていく。

BTraceを使ってみる

アプリのモジュールに手を入れられない、デバッガも使えない、でも実行情報は取得したい…、というときに便利です。

入手と導入

このあたりからBTraceを入手し、任意のディレクトリへ解凍します。
https://kenai.com/projects/btrace/downloads/directory/releases/current
「BTrace導入ディレクトリ\bin」を環境変数に追加しておくと、コマンドプロンプトから使いやすいですね。

トレース対象のアプリを用意

しょーもないサンプルを用意しました。

public class Plus {
    private static int plus(int a, int b) {
        return a + b;
    }
    public static void main(String[] args) {
        for (int i = 0; i < 5000; i++) {
            System.out.println(plus(i, i));
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
            }
        }
    }
}

トレーススクリプトの記述

Plusアプリのplusメソッドからreturnするタイミングで、クラス名、メソッド名、引数、戻り値を取得してみます。以下のファイルを作成し、BTraceTest.javaという名前で保存します。

import com.sun.btrace.AnyType;
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;

@BTrace
public class BTraceTest {
    @OnMethod(
        clazz="Plus", // 適用するクラス名。正規表現も使える。正規表現の場合は"/jp\.co\..*/"のように/で囲む。
        method="plus", // 適用するメソッド名。正規表現も使える。クラス名と同じ。
        location=@Location(Kind.RETURN) // 適用タイミング
    )
    public static void method(
        AnyType[] args,
        @ProbeClassName String className,
        @ProbeMethodName String methodName,
        @Return int ret
    ) {
        String message = "";
        
        message = concat(message, className);
        message = concat(message, "#");
        message = concat(message, methodName);
        message = concat(message, " [");
        message = concat(message, str(args[0]));
        message = concat(message, ", ");
        message = concat(message, str(args[1]));
        message = concat(message, "] return=");
        message = concat(message, str(ret));

        println(message);
    }
}

実行

コマンドプロンプトを開き、まずは普通にアプリを実行します。

> java Plus

続いて、もう一つコマンドプロンプトを開き、jpsコマンドを使ってアプリ(Plus)のプロセスIDを調べます。

> jps
6524 Jps
6408 Plus

6408がアプリのプロセスIDですね。
続いてBTraceを実行します。

> btrace 6408 BTraceTest.java

実行結果はこんな感じです。

  :
Plus#plus [1025, 1025] return=2050
Plus#plus [1026, 1026] return=2052
Plus#plus [1027, 1027] return=2054
Plus#plus [1028, 1028] return=2056
Plus#plus [1029, 1029] return=2058
  :