Akira's Blog

神奈川在住のITエンジニアの雑記です。主にプログラミング(Perl, Java など)やネットワーク技術についての小ネタを、ちょっとずつ書いていきます。

Javaのスタックトレースを解析する時のコツ

フレームワークなどを多用した大規模なJavaプログラムにおいて、エラーが起きてログにスタックトレースが出ると、その量が膨大過ぎてどうやって解析すれば良いのか困ることがある。そんな時に自分が心掛けていることを書く。

まず、アプリケーション独自の部分を見る

通常、スタックトレースには、フレームワークのコードの部分とアプリケーション独自のコードの部分が入り混じる。問題を引き起こしているのは、フレームワークよりアプリケーション独自の部分であることの方が多いので、まずはアプリケーション独自の部分を見て、その部分のコードを解析するのが良いと思う。それで、アプリケーション独自の部分に問題がなければ、フレームワークの方を疑う。

一番下の「Caused by」ブロックの一番上のメソッドのコードを見る

スタックトレースが「Caused by ・・・」で多段になっていたら、一番下の「Caused by」ブロックの一番上のメソッドが大元の例外の発生源なので、そのソースコードを見ると何か分かるかも。

例えば、スタックトレース

ExceptionA
    at method3
    at method2
    at method1
Caused by: ExceptionB
    at method5
    at method4
    at method3
Caused by: ExceptionC
    at method8
    at method7
    at method6
    at method5

となっていたら、大元の例外の発生源は method8 なので、その処理内容を見れば何か分かるかもしれない。なお、直近の例外の発生源であるmethod3 を見ると有効な時もある。


ちなみに、上記についての簡単なサンプルプログラムと、その実行結果を以下に示す。

public class ExceptionChainSample {

    public static void main(String[] args) {
        new ExceptionChainSample().exec();
    }

    private void exec() {
        try {
            method1();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    private void method1()  throws Exception {
        method2();
    }
    private void method2()  throws Exception {
        method3();
    }
    private void method3() throws Exception {
        try {
            method4();
        } catch (Exception ex) {
            throw new TransformedException(ex);
        }
    }
    private void method4() throws Exception {
        method5();
    }
    private void method5() throws Exception {
        try {
            method6();
        } catch (Exception ex) {
            throw new TransformedException(ex);
        }
    }
    private void method6() throws Exception {
        method7();
    }
    private void method7() throws Exception {
        method8();
    }
    private void method8() throws Exception {
        throw new OrgException("test exception");
    }

    private class OrgException extends Exception {
        OrgException(String msg) {
            super(msg);
        }
    }
    private class TransformedException extends Exception {
        TransformedException(Throwable th) {
            super(th);
        }
    }
}


実行結果は以下。

ExceptionChainSample$TransformedException: ExceptionChainSample$TransformedException: ExceptionChainSample$OrgException: test exception
	at ExceptionChainSample.method3(ExceptionChainSample.java:24)
	at ExceptionChainSample.method2(ExceptionChainSample.java:18)
	at ExceptionChainSample.method1(ExceptionChainSample.java:15)
	at ExceptionChainSample.exec(ExceptionChainSample.java:9)
	at ExceptionChainSample.main(ExceptionChainSample.java:4)
Caused by: ExceptionChainSample$TransformedException: ExceptionChainSample$OrgException: test exception
	at ExceptionChainSample.method5(ExceptionChainSample.java:34)
	at ExceptionChainSample.method4(ExceptionChainSample.java:28)
	at ExceptionChainSample.method3(ExceptionChainSample.java:22)
	... 4 more
Caused by: ExceptionChainSample$OrgException: test exception
	at ExceptionChainSample.method8(ExceptionChainSample.java:44)
	at ExceptionChainSample.method7(ExceptionChainSample.java:41)
	at ExceptionChainSample.method6(ExceptionChainSample.java:38)
	at ExceptionChainSample.method5(ExceptionChainSample.java:32)
	... 6 more


エラーが起きて膨大なスタックトレースが出力されると途方に暮れそうになるが、ここに書いたようなテクニックを駆使しつつ、何とか対応していきたい。