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()는 스택 추적에 끝나는 실제 방법, Hah.method()가 동적으로 생성 된입니다 반면에 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의 한 가지 장점은 전체 스택에 대해 비용이 많이 드는 정보를 수집 할 필요가 없기 때문에 성능이 향상된다는 것입니다. –

+0

그래? [Files.walk() API에서 "걷기"를 본 적이 있지만 기대했던대로하지 않습니다.] (https://blog.jooq.org/2014/01/24/java-8) -friday-goodies-the-new-new-io-apis /) –