使用go-callvis查看函数调用流程

使用go-callvis查看逻辑复杂的项目的函数调用流程,减少理解成本

go-callvis是什么

go-callvis是代码调用链路可视化工具,是代码方法级别的调用关系,主要用于代码设计。可视化工具可以将代码间的调用关系通过图表的方式展示出来,如下图。

如何生成调用关系图

go-callvis除了可以生成图片文件,还可以生成svg图,它默认会启动一个Web Server,我们可以在浏览器访问它的地址,在页面上实现交互式的浏览调用关系。

SVG:

1
2
SVG是一种用XML定义的语言,用来描述二维矢量及矢量/栅格图形。
SVG图形是可交互的和动态的,可以在SVG文件中嵌入动画元素或通过脚本来定义动画。

下面是一段SVG代码:

1
2
3
<g id="a_clust3"><a xlink:href="/?f=github.com/goccy/go-graphviz/cgraph" xlink:title="package: github.com/goccy/go&#45;graphviz/cgraph">
<polygon fill="#ffffe0" stroke="#000000" stroke-width=".8" points="861.8909,-442.8 861.8909,-521.8 972.5803,-521.8 972.5803,-442.8 861.8909,-442.8"/>
<text text-anchor="middle" x="917.2356" y="-503.4" font-family="Tahoma bold" font-size="16.00" fill="#000000">cgraph</text>

可以看到和HTML类似,同样是一种标记语言。

go-callvis使用介绍

首先使用go get -u github.com/ofabry/go-callvis 命令进行安装,安装完成后go-callvis将出现在你得GOPATH/bin目录下。

命令行参数解释:

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
go-callvis: visualize call graph of a Go program.

Usage:
go-callvis [flags] package //package即想要进行分析的包名,注意:package必须是main包或者包含单元测试的包,原因稍候介绍


Flags:

-cacheDir string
如果指定了缓存目录,生成过的图片将被保存下来,后续使用时不需要再渲染
-debug
开启调试日志.
-file string
指定输出文件名,使用后将不在启动Web Server
-focus string
定位到指定的package,package可以是包名也可以是包的import路径,默认main包
-format string
指定输出文件格式[svg | png | jpg | ...] (default "svg")
-graphviz
使用本地安装的graphviz的dot命令,否则使用graphviz的go库
-group string
分组方式: packages and/or types [pkg, type] (separated by comma) (default "pkg")
-http string
Web Server地址. (default ":7878")
-ignore string
忽略的packages,多个使用逗号分隔。(使用前缀匹配)
-include string
必须包含的packages,多个使用逗号分隔。优先级比ignore和limit高(使用前缀匹配)
-limit string
限制的packages,多个使用逗号分隔(使用前缀匹配)
-minlen uint
两个节点直接最小连线长度(用于更宽的输出). (default 2)
-nodesep float
同一列中两个相邻节点之间的最小空间(用于更高的输出). (default 0.35)
-nodeshape string
节点形状 (查看graphvis文档,获取更多可用值) (default "box")
-nodestyle string
节点style(查看graphvis文档,获取更多可用值) (default "filled,rounded")
-nointer
忽略未导出的方法
-nostd
忽略标准库的方法
-rankdir string
对齐方式 [LR 调用关系从左到右| RL 从右到左| TB 从上到下| BT 从下到上] (default "LR")
-skipbrowser
不打开浏览器
-tags build tags
支持传入build tags
-tests
包含测试代码
-version
Show version and exit.

使用示例

1. 最简单的命令如下:

1
go-callvis .

此命令会在当前目录进行分析,如果没有错误,会自动打开浏览器,在浏览器中展示图

2. 指定package

1
go-callvis github.com/ofabry/go-callvis

指定的package是main,工具将以main方法作为起始点进行链路生成

3. 指定包含单元测试方法的package

1
go-callvis -tests yourpackage

如果不想从main方法开始,可以使用-tests参数,在想要进行链路生成的package下面创建一个单元测试方法,测试方法中调用你想要作为起始点的方法。

4. 输出结果到文件

以上都是打开浏览器进行交互式浏览和操作,如果只要输出文件,可以使用-file参数

1
go-callvis -file yourfilename -format png  yourpackage

5. include、limit、ignore参数

这三个参数用来控制过滤哪些调用关系(pkg1.FuncA -> pkg2.FuncB,形成一条调用关系,pkg1.FuncA为caller,pkg2.FuncB为callee)。例如代码中频繁出现的log包方法调用,没必要输出到链路中。可以使用ignore参数进行过滤

1
go-callvis -ignore yourlogpkg yourpackage
  1. 当调用关系中caller的pkg或者callee的pkg有任意一个在include中,则这条关系被保留。
  2. 不满足1时,当调用关系中caller的pkg或者callee的pkg有任意一个不在limit中,则这条关系被过滤。
  3. 不满足1时,当调用关系中caller的pkg或者callee的pkg有任意一个在ignore中,则这条关系被过滤。

6. 过滤标准库

过滤掉代码中频繁使用的标准库方法调用,例如:fmt、math、strings等

1
go-callvis -nostd yourpackage

7. build tags

go build命令可以允许我们传入-tags参数,来控制编译的版本

1
go build -tags release 

例如有两个配置文件dev_config.go和release_config.go,内容分别为

dev_config.go

1
2
3
4
5
 // +build dev

package main

var version = "DEV"

release_config.go

1
2
3
4
5
// +build release

package main

const version = "RELEASE"

每个文件都有一个编译选项(+build),编译器会根据-tags传入的参数识别应该编译哪一个文件。从而达到区分环境的效果。
go-callvis的tags参数同理。

本地代码使用实战

以kcp-go为例

1
go-callvis -nostd examples/echo.go
image-20230807115955151

main包调用情况,点击黄色区域可以查看kcp包的调用情况(会耗时几分钟)

查看函数调用最密集的地方,也是最核心的地方,如下图便是Input,这也是kcp-go中最核心的代码

效果图说明