2016-09-26 11 views
6

とスタックフレームを生成するには、私は頻繁に持っているしたいと思います:どのように動的に優れたデバッグのためのデバッグログ情報

Exception 
    at com.example.blah.Something.method() 
    at com.example.blah.Xyz.otherMethod() 
    at com.example.hello.World.foo() 
    at com.example.debug.version_3_8_0.debug_info_something.Hah.method() // synthetic method 
    at com.example.x.A.wrappingMethod() 

デバッグスタックフレーム上に示したように、動的除き、ちょうどjava.lang.reflect.Proxyのように、生成されますプロキシーで終わる完全修飾メソッド名全体を完全に制御したいと思っています。呼び出しサイトで

、私は愚かなと、このような単純なものだろう:あなたが見ることができるように

public void wrappingMethod() { 
    run("com.example.debug.version_3_8_0.debug_info_something.Hah.method()",() -> { 
     World.foo(); 
    }); 
} 

を、wrappingMethod()は、スタックトレースに終わる本当の方法であり、​​は、動的に生成されます一方、World.foo()はもう一度実際の方法です。

はい、これは既に深い深いスタックトレースを汚染することがわかります。ご心配なく。私には理由がある。

これを行うには(単純な)方法がありますか?

+1

私はこの分野に非常に精通していませんが、このようなことはバイトコードレベルで行うことができますが、言語で可能かどうかはわかりません。 –

+0

@ Meguy26:JDKの外で特別な依存関係がなくても実装できるのであれば、バイトコードレベルのソリューションはうまくいきます。しかし、私はまた、Bytebuddy –

答えて

8

この問題解決するコード生成のための必要がありません:コード生成で

static void run(String name, Runnable runnable) { 
    try { 
    runnable.run(); 
    } catch (Throwable throwable) { 
    StackTraceElement[] stackTraceElements = throwable.getStackTrace(); 
    StackTraceElement[] currentStackTrace = new Throwable().getStackTrace(); 
    if (stackTraceElements != null && currentStackTrace != null) { // if disabled 
     int currentStackSize = currentStackStrace.length; 
     int currentFrame = stackTraceElements.length - currentStackSize - 1; 
     int methodIndex = name.lastIndexOf('.'); 
     int argumentIndex = name.indexOf('('); 
     stackTraceElements[currentFrame] = new StackTraceElement(
      name.substring(0, methodIndex), 
      name.substring(methodIndex + 1, argumentIndex), 
      null, // file name is optional 
      -1); // line number is optional 
     throwable.setStackTrace(stackTraceElements); 
    } 
    throw throwable; 
    } 
} 

を、あなたは、名前のメソッドを追加するメソッド内で呼び出しサイトを再定義し、フレームをほどくと、生成されたメソッドを呼び出すことができますしかし、これははるかに多くの作業になり、決して均等に安定することはありません。

この戦略は、フレームワークのテストではかなり一般的なアプローチです.we do it a lot in Mockitoと同様に、例外スタックフレームを書き換えることで魔法を隠すためにJRebelなどの他のユーティリティも使用します。

Java 9を使用する場合は、Stack Walker APIを使用してこのような操作を行う方が効率的です。

+0

* "Stack Walker" *のような依存関係を使用するワーキングソリューションを受け入れることになります。つまり、Stream.of(stackTraceElements)ではなく、 :) –

+1

スタックウォーカーAPIの利点の1つは、コストがかさむスタック全体に関する情報を収集する必要がないため、パフォーマンスが向上します。 –

+0

それはそうですか? [Files.walk()APIの前に "歩いている"と思っていて、あなたが期待することはできません](https://blog.jooq.org/2014/01/24/java-8 -friday-goodies-the-new-new-io-apis /) –

関連する問題