9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

フューチャーAdvent Calendar 2020

Day 8

Goでコールグラフを自作してみた

Last updated at Posted at 2020-12-07

フューチャー Advent Calendar 2020の8日目の記事です。

普段はJavaの静的解析をすることが多いですが、今回はGoの静的解析に手をつけてみました。本記事ではGoでコールグラフ自作をしてみたいと思います。すでにofabry/go-callvis: Visualize call graph of a Go program using dot (Graphviz)といったコールグラフ作成ツールがありますが、今回はあえてコールグラフを自作して既存のツールを使うだけではできない拡張をしてみました。

なお私はGoはあまり書いたことがないのでツッコミどころは多々あるかと思います。気になる点などございましたらご指摘いただけると幸いです。

シンプルなコールグラフ作成

GoではGoのソースコードの静的解析を行うライブラリが準標準パッケージとして用意されているようで、それを使うだけで簡単にコールグラフを可視化することができました。まずは何も考えずにコールグラフを作成してみました。

今回はisucon/isucon10-qualify: ISUCON10予選のソースコードを対象にコールグラフを作成してみましょう。コールグラフは関数をノード、関数呼び出しをエッジとしており、ノードにはパッケージ名.関数名というラベルを、エッジにはfile=ファイル名, Line=行番号というラベルを表示しています。

解析結果 その1(何も考えず全て表示)

下記のようなグラフになりました(オリジナルの画像は大きすぎるせいかQiitaにアップロードできなかったので縮小しています)
解析に使用したソースコードは解析結果 その1です。

graph_base.png

あまりにも巨大で何が何だかよくわかりませんね。グラフを見てみると、ISUCONではそんなに重要でないログ出力などが多数含まれています。まずは特に重要なCRUDに注目したいということで、思い切ってcalleeがsql, sqlx以外のpackageへ繋がるエッジは除外してみましょう。

解析結果 その2(sql,sqlx以外のエッジを除去)

これくらいなら全容が把握できそうと思える規模になってきました。
解析に使用したソースコードは解析結果 その2です。

graph_crud.png

これを見ればどの関数でCRUDが行われているか把握できそうですね。
ただし、これだけではどのエンドポイントからどのCRUDが行われているかわからないので今度はエンドポイントを表すノードを追加してみましょう。

解析結果 その3(エンドポイントのノードを追加)

どのエンドポイントでCRUDが行われているかわかるようになりました。本当はどのテーブルのどのカラムにアクセスしているかといった情報も載せたかったのですが、そこまでは手が回りませんでした。
解析に使用したソースコードは解析結果 その3です。
(わかりやすいようにエンドポイントはlightgreenで着色しています)
graph_add_endpoint.png

まとめ

Goの準標準パッケージがとても充実しており、サクッと静的解析できて素晴らしいなと感動しました。

単にコールグラフを作るだけなら既存のツール1を使えば済みますが、自作することで自由にカスタマイズすることができ、知りたいこと、伝えたいことにフォーカスしたコールグラフが作成できそうですね。

また今回のようにCRUDだけに注目するのではなく、開発したアプリをうまく可視化することで後からチームに入ってきた人が設計を理解する資料の一つとして使ったり、あるいは既存のLintでは対応できない項目のチェックができたり2とうまく活用すれば静的解析はとても有用そうだと思いました。

(余談ですがssautilパッケージのAllPackages関数はssautil · pkg.go.devのドキュメントには Load function in LoadAllSyntax mode. と書かれているので LoadAllSyntax という定数でモード指定することを推奨しているような気がするのですが、このpackages · pkg.go.devをみるとLoadAllSyntaxはdeprecatedなんですよね。使うべきなのかそうでないのか…)

参考

  1. ofabry/go-callvis: Visualize call graph of a Go program using dot (Graphviz)

  2. 特定の関数やメソッドの呼び出しを検知するLinterを作った - tenntenn.dev

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?