java - 如何使用调试日志信息动态生成堆栈帧

标签 java reflection bytecode proxy-classes

为了更好的调试,我经常希望:

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() 又是一个真正的方法。

是的,我知道这会污染已经很深的堆栈跟踪。别担心。我有我的理由。

是否有一种(简单的)方法可以做到这一点或与上述类似的方法?

最佳答案

不需要代码生成来解决这个问题:

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 进行此类操作会更有效。 .

关于java - 如何使用调试日志信息动态生成堆栈帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39712695/

相关文章:

java - 反射:获取具有任意数量参数的方法并按原样使用它

Java 8 : Merge String[] and int[] into Object[] when verifying bytecode

java - 如何使用rejava (reJ) 来调试jave 字节码? (java字节码编辑器)

java - 绘制多个函数时如何消除一组重复的 X 值?

.net - 从反射属性中检索反射类型的值

java - 从长期值(value)中获取时间

reflection - 在 D 中透明地同步对象中的任意属性

java - 避免 getfield 操作码

java - 如何将oracle RAW数据类型(保存为字符串)转换为java String?

java - 即使第一个线程使用 ReentrantLock 锁定,第二个线程也会执行