How to dynamically generate a stack frame with debug log information

For better debugging, I would often like to:

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.xAwrappingMethod() 

The debug stack frame, as shown above, will be dynamically generated, like java.lang.reflect.Proxy , except that I would like to fully control the entire fully qualified name of the method, which ends on the proxy server.

On the call site, I would do something stupid and simple:

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

As you can see, wrappingMethod() is a real method that ends with a stack trace, Hah.method() is a dynamically generated method, while World.foo() again a real method.

Yes, I know that it pollutes the already deep deep traces of the stack. Do not worry about it. I have a reason.

Is there a (simple) way to do this or something similar as above?

+6
source share
1 answer

There is no need to generate code to solve this problem:

 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; } } 

With code generation, you can add a method with a name, redefine the call site within the method, untwist the frame and call the generated method, but this will work much more and will never be equally stable.

This strategy is a fairly common testing approach, we do it a lot in Mockito , and other utilities like JRebel hide their magic by overwriting frames of the exception stack.

When using Java 9, it would be more efficient to perform such manipulations using the Walker stack API.

+8
source

All Articles