v0_2 自动获取所跟踪函数的函数名
# v0.2 自动获取所跟踪函数的函数名
要解决“调用 Trace 时需要手动显式传入要跟踪的函数名”的问题,也就是要让 Trace 函数能够自动获取到它跟踪函数的函数名信息。
带来的好处:
在手动显式传入的情况下:
defer Trace("foo")()
1
一旦实现了自动获取函数名,所有支持函数调用链跟踪的函数都只需使用下面调用形式的 Trace 函数就可以了:
defer Trace()()
1
这种一致的 Trace 函数调用方式也为后续的自动向代码中注入 Trace 函数奠定了基础。
**解决方案:**实现 Trace 函数对它跟踪函数名的自动获取,需要借助 Go 标准库 runtime 包的帮助。
// trace1/trace.go
func Trace() func() {
pc, _, _, ok := runtime.Caller(1)
if !ok {
panic("not found caller")
}
fn := runtime.FuncForPC(pc)
name := fn.Name()
println("enter:", name)
return func() { println("exit:", name) }
}
func foo() {
defer Trace()()
bar()
}
func bar() {
defer Trace()()
}
func main() {
defer Trace()()
foo()
}
/*
enter: main.main
enter: main.foo
enter: main.bar
exit: main.bar
exit: main.foo
exit: main.main
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
通过 runtime.Caller 函数获得当前 Goroutine 的函数调用栈上的信息,runtime.Caller 的参数标识的是要获取的是哪一个栈帧的信息。当参数为 0 时,返回的是 Caller 函数的调用者的函数信息,在这里就是 Trace 函数。但我们需要的是 Trace 函数的调用者的信息,于是我们传入 1。
Caller 函数有四个返回值:
- 第一个返回值代表的是程序计数(pc);
- 第二个和第三个参数代表对应函数所在的源文件名以及所在行数,这里暂时不需要;
- 最后一个参数代表是否能成功获取这些信息,如果获取失败,抛出 panic。
通过 runtime.FuncForPC 函数和程序计数器(PC)得到被跟踪函数的函数名称。
上次更新: 2022/10/06, 00:04:41