bpftrace是基于eBPF进行动态追踪的工具,本文将通过一个示例来展示,如何使用bpftrace跟踪golang程序。
go程序
go程序实现一个简单的功能:两个整数a和b相加,并返回结果。代码如下:
package main
import "fmt"
//go:noinline
func add(a, b int64) int64 {
return a + b
}
func main() {
a := int64(1)
r := add(a, int64(2))
fmt.Println(r)
}
bpftrace脚本
bpftrace实现的功能有两部分:一是追踪 add 函数的输入参数,并打印输出;二是追踪 add 函数的返回值,并打印输出。代码如下:
uprobe:./example:main.add
{
printf("arg1:%d\n", sarg0);
printf("arg2:%d\n", sarg1);
}
ur:./example:main.add
{
printf("retval:%d\n", retval);
}
运行
首先,在一个终端运行bpftrace脚本,启动跟踪:
bpftrace ./example.bt
然后,在另一个终端运行golang程序:
./example
3
此时,可以在bpftrace脚本窗口,看到对应的输出。
Attaching 2 probes...
arg1:1
arg2:2
retval:3
总结
本文展示了bpftrace追踪golang程序的基本方法,使用bpftrace可以在不重启服务,不修改代码的情况下,无侵入地追踪到程序的运行参数。为线上定位问题、服务监测等提供了比较便利的方式。
但是,由于bpftrace所追踪的是C语言函数,而golang中函数定义、数据类型、编译器优化等,都给bpftrace的追踪带来一定的困难。
下篇文章将讨论:
- 上文的golang代码中,add函数上加了一行代码 go:noinline 有什么作用?为什么需要加?
注:关于bpftrace相关知识,请参考: