フレームワークなどを多用した大規模な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
エラーが起きて膨大なスタックトレースが出力されると途方に暮れそうになるが、ここに書いたようなテクニックを駆使しつつ、何とか対応していきたい。