如何使用附加信息(如参数)在 java 中创建自定义堆栈跟踪?

how to create a custom stacktrace in java with additional info (like parameters)?

我被分配了一个任务来创建一个自定义堆栈跟踪,比如为某些指定的函数输出到日志文件,但我不仅要使用 class 和方法名称,我还必须输出参数及其它们值。

这应该是一个单独的 jar,之后可以 运行 用于任何 java 项目。

我什至不知道这样的事情是否可能,更不用说从哪里开始了。 任何帮助将不胜感激。

编辑:还有其他库通过使用本机 VM api 来做到这一点:https://github.com/cretz/stackparam 它还修改了 Throwable class 以始终打印修改后的堆栈跟踪。

我能想到的唯一可能的方法是使用代理和工具化,但是需要在启动命令行中添加代理。
然后我将使用 ASM 库注册转换器以转换每个 class(请记住,一些基本的 java classes 可能已经加载)并将代码添加到每个方法调用的开头以手动跟踪每个方法 class 并将其传递给我的图书馆以跟踪它们:

// note that parameters names might not exist in runtime if code was compiled without a flag to include them.
public void doSomething(String name, int something) {
    MyLib.enterMethod(ThisClass.class, new MethodSignature(void.class, String.class, int.class), new Argument("name", name), new Argument("something", something));
    try {
        // original code
    } finally { // so we don't need to care about return in the middle of original code or exceptions
        MyLib.exitMethod();
    }
}

enterMethod 会将调用帧添加到某个队列,exitMethod 会删除最后添加的帧。请注意,您应该为每个线程设置单独的队列,使用一些 Map<Thread, MyFrame>ThreadLocal 对线程使用一些弱引用可能是个好主意。

然后您可以使用该队列中的帧来创建自己的堆栈跟踪。
但是做这样的事情可能会大大降低性能 - 不仅仅是因为这段代码的成本,而是将它添加到每个 setter/getter 可能会导致该方法永远不会被内联并进一步影响性能。

所以这是可能的,但我真的不建议这样做。
此外,其他库添加的一些其他转换器可能会影响结果,最好也将您的堆栈跟踪与原始堆栈跟踪进行比较,以找到您未转换的任何缺失方法 - 就像本机方法一样,并将它们添加到您的堆栈跟踪但没有那个附加数据。

如果您确实也需要支持本地方法 - 那么您可以创建更高级的转换器,在调用本地方法之前和之后添加 enterMethod/exitMethod

此外,如果这仅用于调试,您可以使用调试 API,因此它只能用作调试器。