首页 > 解决方案 > 如何使用附加信息(如参数)在 java 中创建自定义堆栈跟踪?

问题描述

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

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

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

标签: javafunctionjarstack-trace

解决方案


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

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

// 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,因此它只能用作调试器。


推荐阅读