看源码的一个比较好的思路是: 先从宏观上对系统内部模块的调用关系有一个大概的认识. 这个过程又分静态分析和动态分析. 动态分析很简单, 直接对内存数据进行采样即可, 比如 Golang 的 pprof. 动态分析有一个缺点是依赖于流量, 或者说访问数据, 不同的访问数据往往会造成不同的调用关系. 静态分析的话现在市面上也有很多好用的开源工具, 我们今天看一下 Golang 的代码静态依赖分析怎么来做.
Golang 代码的静态分析尤其简单, 为什么? Golang 语法方面, 我们在调用一个 package 的时候, 需要 import. 同时, 如果我们代码中对一个 package 没有引用而又把包 import 进来, 这个时候 Golang 的编译器是会报错的. 这两点意味着我们可以通过分析 import 语句块来得到我们包内部的调用关系.
当然尽管上面原理说的比较简单, 但是实现起来还是有一些坑. 没关系, 我帮你们实现了. 链接: http://github.com/legendtkl/godag . 取名 DAG 也是因为包之间的依赖其实就是一个 DAG.
1. 安装
go get -u github.com/legendtkl/godag
我在实现的时候包里面没有引用第三方包, 这样也是为了不能翻墙的同学 go get 无障碍.
2. 使用
以 beego 项目为例, 分析其内部的包之间的调用关系.
godag --pkg_name=github.com/astaxie/beego --pkg_path=/Users/kltao/code/go/src/github.com/astaxie/beego --depth=1 --dot_file_path=a.dot
godag 支持四个参数:
pkg_name: 要分析的 package 名称, 必填
pkg_path: package 存放在本地的目录, 必填
depth: 分析的代码深度. 举个例子, 如果 depth 为 1, 我们则会分析包: beego/cache,beego/context; 而如果 depth 为 2, 则分析这些包: beego/cache/redis,beego/cache/ssdb 等.
dotfilepath: 是我们输出的 dot 文件, 下面细说
3. 输出
3.1 dot
godag 会输出一个 .dot 文件. dot 是一种绘图语言, 它可以方便你采用图形的方式快速, 直观地表达一些想法, 比如描述某个问题的解决方案, 构思一个程序的流程, 澄清一堆貌似散乱无章的事物之间的联系. 举个列子, 下面列出 dot 文件以及对应的流程图.
digraph graphname {a -> b -> c;
b -> d;
}
对应流程图.
关于 dot 文件更详细的信息可以参考: DOT(graph description language) https://en.wikipedia.org/wiki/DOT_(graph_description_language) . 我们生产的 dot 文件内容如下.
- digraph G {
- "beego/utils" -> "beego/session"
- "beego/logs" -> "beego/logs"
- "beego/utils" -> "beego"
- }
3.2 可视化
dot 文件的可视化可以使用 graphviz.graphviz 的安装比较简单, 比如 Mac 上安装命令如下
brew install graphviz
dot 文件可视化, 使用 dot 命令, 比如生成 png 图.
dot -Tpng godag.dot> godag.png
4. 举例
比如 depth 为 1 的时候, beego 的内部依赖图如下.
depth 为 2 的时候, 依赖图如下.
5. 参考
- godap https://github.com/legendtkl/godag
- DOT(graph description language) https://en.wikipedia.org/wiki/DOT_(graph_description_language)
欢迎提 issue 和 pr.
来源: https://juejin.im/entry/5ac9acbd518825555e5e1bf6