Thred からデバッグ情報を取得する

Thredからのデバッグ情報の取得

Thread のスタック情報から現在のメソッド名や行数などのデバッグ情報を取得。

public class Debug {
    public static String currentFile() {
        return Thread.currentThread().getStackTrace()[2].getFileName();
    }
    public static String currentClass() {
        return Thread.currentThread().getStackTrace()[2].getClassName();
    }
    public static String currentMethod() {
        return Thread.currentThread().getStackTrace()[2].getMethodName();
    }
    public static int currentLineNumber() {
        return Thread.currentThread().getStackTrace()[2].getLineNumber();
    }
    ・・

以下の様に呼び出すと、

public class Example {
    @org.junit.Test public void method() {
        System.out.println(Debug.currentFile());
        System.out.println(Debug.currentClass());
        System.out.println(Debug.currentMethod());
        System.out.println(Debug.currentLineNumber());
    }
}

スタック情報からメソッド名や行番号など、以下の様な出力が得られる。

Example.java
etc9.Example
method
8

スレッドダンプの取得

スレッドダンプは標準エラー出力にはかれるので、標準出力を横取りすれば文字列として得られる。

    public static synchronized String stackTrace1() {
        PrintStream savedErr = System.err;
        ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
        PrintStream stdErr = new PrintStream(baosErr);

        System.setErr(stdErr);
        Thread.dumpStack();
        System.setErr(savedErr);

        return baosErr.toString();
    }

以下のようなコードから呼び出すと、

public class Example {
    @org.junit.Test public void method() {
        System.out.println(Debug.stackTrace1());
    }
}

スタックトレースが得られる。

java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1206)
    at etc9.Debug.stackTrace1(Debug.java:34)
    at etc9.Example.method(Example.java:5)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    ・・・

少しましなスレッドダンプの取得

標準エラー出力を横取りするのは気持ち悪い場合は、Exception から文字列としてスタックトレースを取得できる。

    public static String stackTrace2() {
        return stackTraceString(new Exception("Stack trace"));
    }
    public static String stackTraceString(Throwable t) {
        StringWriter writer = new StringWriter();
        t.printStackTrace(new PrintWriter(writer));
        return writer.toString();
    }

として同様にスタックトレースを文字列として取得できる。

も少しましなスレッドダンプの取得

Exception からでなく、Thread からもスタックトレース情報が取れる。

    public static String stackTrace3() {
        return Thread.currentThread() +  "\n" +
            stackTraceString(Thread.currentThread().getStackTrace());
    }   
    public static String stackTraceString(StackTraceElement[] stackTraceElements) {
        StringBuilder sb = new StringBuilder();
        for(StackTraceElement stackTraceElement : stackTraceElements) {
            sb.append("    ");
            sb.append(stackTraceElement.toString());
            sb.append("\n");
        }
        return sb.toString();
    }

以下のようなスタックトレースが文字列として得られる。

Thread[main,5,main]
    java.lang.Thread.getStackTrace(Thread.java:1436)
    etc9.Debug.stackTrace3(Debug.java:53)
    etc9.Example.method(Example.java:5)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    ・・・

全スレッドのスレッドダンプ

現在のスレッドだけでなく、全てのスレッドのダンプを得るには Thread.getAllStackTraces() が使える。

    public static String allStackTrace() {
        StringBuilder sb = new StringBuilder();
        for(Entry<Thread, StackTraceElement[]> entry :
                Thread.getAllStackTraces().entrySet()) {
            sb.append(entry.getKey());
            sb.append("\n");
            sb.append(stackTraceString(entry.getValue()));
            sb.append("\n");
        }
        return sb.toString();
    }
    public static String stackTraceString(StackTraceElement[] stackTraceElements) {
        StringBuilder sb = new StringBuilder();
        for(StackTraceElement ste : stackTraceElements) {
            sb.append("    ");
            sb.append(ste.toString());
            sb.append("\n");
        }
        return sb.toString();
    }

こんな感じで呼ぶと

public class Example {
    @org.junit.Test public void method() {
        System.out.println(Debug.allStackTrace());
    }
}

全てのスレッドのトレースが取得できる。

Thread[Signal Dispatcher,9,system]

Thread[Attach Listener,5,system]

Thread[main,5,main]
    java.lang.Thread.dumpThreads(Native Method)
    java.lang.Thread.getAllStackTraces(Thread.java:1487)
    etc9.Debug.allStackTrace(Debug.java:61)
    ・・・

Thread[Reference Handler,10,system]
    java.lang.Object.wait(Native Method)

・・・