テストカバレッジや静的コード解析ツールなどを使う場合、その時その時のスコアは分かりますが「数ヶ月前と比べてどうだったか」というのも知りたいですよね
そうなると継続的に指標を取ってどこかに記録しておく必要があると思います
イメージとしてはJenkinsのCoverage表示のPluginで出てくるグラフです
「ココらへんでテストコードガッツリ書いたので上がってる!」みたいなことがやりたいわけです
例としてカバレッジを上げましたが他にも独自で指標を取って変化を追いたいというモチベーションがずっとありました
なるべく簡単に実現したいですね
そのときに考えていたのが
可視化用のサービスを使う(未調査)
- そのためだけに使うのはちょっと大げさすぎる気が。。。
spreadsheetなどに記録してRedashやdataportalで可視化する
- Redashはサーバ用意しないといけないのでそこまでするのは。。。
- dataportalであればサーバも必要ないし良さそうな気がしますがすでにそういう手段はやったことがあるので今回は除外
- READMEなどから見れたらいいかも
SVGを使ってグラフを作ってそれを表示させる
- データ自体はjsonで持たせれば後でなんとでもできる
- 先にデータ取得を始めるということも可能
- 他サービスなどのAPIを使わなくてもなんとかできそう
- データ自体はjsonで持たせれば後でなんとでもできる
みたいなことを考えていました
そうしているうちにSVGを使って試したくなってきてしまったので試してみることにしました
方法
最初jsonを読み込んでスクラッチでグラフっぽい感じの推移を表現しようと思ったのですがめちゃくちゃ時間が取られそうに思えたのでやめました
今回はGoogleChartsを使ってjsonからSVGグラフを表示させる部分は楽させてもらいました
流れ
- 対象指標を定期的に計測し保存
- git管理
- jsonを保存
- GoogleChartsでjsonからデータを読み込むhtmlを用意
- ローカルでstaticサーバを起動させSVGを生成
- puppeteerでアクセスしてSVGの箇所を切り出してファイルに保存
- SVGをREADMEに設置するなりartifactに上げるなりしていつでも見れるようにする
定期的に計測
本来だったら下記のフォーマットになるようスクリプトなり何なりを書く
後の工程でGoogleChartに食わせるのでそれに合わせたjsonの形式にしておく
- data.json
[ ["Date", "hoge", "fuga", "piyo"], ["2019-06-20", 37.8, 80.8, 41.8], ["2019-06-21", 30.9, 69.5, 32.4], ["2019-06-22", 25.4, 57, 25.7], ["2019-06-23", 11.7, 18.8, 10.5], ["2019-06-24", 11.9, 17.6, 10.4], ["2019-06-25", 8.8, 13.6, 7.7], ["2019-06-26", 7.6, 12.3, 9.6], ["2019-06-27", 12.3, 29.2, 10.6], ["2019-06-28", 16.9, 42.9, 14.8], ["2019-06-29", 12.8, 30.9, 11.6], ["2019-06-30", 5.3, 7.9, 4.7] ]
GoogleChartsを使うHTMLを用意し表示させる
とりあえずサンプルをちょっといじって表示できるところまでのものを用意する
arrayToDataTable
でjsonのデータをそのまま使うことができます
- index.html
<html> <head> <!--Load the AJAX API--> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <script type="text/javascript"> document.fonts.ready.then(() => { // Load the Visualization API and the corechart package. google.charts.load('current', {'packages':['line']}); // Set a callback to run when the Google Visualization API is loaded. google.charts.setOnLoadCallback(drawChart); // Callback that creates and populates a data table, // instantiates the pie chart, passes in the data and // draws it. }); function drawChart() { const httpRequest = new XMLHttpRequest(); httpRequest.open('GET', 'data.json'); httpRequest.send(); httpRequest.onreadystatechange = function() { if (httpRequest.readyState == 4 && httpRequest.status == 200){ var httpResult = JSON.parse(httpRequest.responseText); var data = google.visualization.arrayToDataTable(httpResult); var options = { title: 'Company Performance', curveType: 'function', legend: { position: 'bottom' }, height: 300 }; var chart = new google.charts.Line(document.getElementById('chart_div')); chart.draw(data, google.charts.Line.convertOptions(options)); } }; } </script> </head> <body> <div id="chart_div"></div> </body> </html>
staticサーバを起動する
pythonさえが入ってればとくに追加でインストールは不要
python -m http.server 8080 # python2の場合は # python -m SimpleHTTPServer 8080
8080番にアクセスしてみる
jsonから持ってきたデータをもとにグラフが表示されました
puppeteerでSVGの部分だけ切り出す
まぁあとはよしなにやるだけですね
- app.js
const puppeteer = require('puppeteer'); const fs = require('fs'); (async() => { const browser = await puppeteer.launch({ args: [ '--no-sandbox', '--disable-setuid-sandbox' ] }); const page = await browser.newPage(); page.on('pageerror', error => { console.log('Console Error', error.message) }); page.on('response', response => { console.log(response.status(), response.url()); if (300 > response.status() && 200 <= response.status()) return; console.warn('status error', response.status(), response.url()); }); await page.goto('http://192.168.30.94:8080/', { waitUntil: 'networkidle0' }); // ローカルサーバのURL await page.screenshot({path: 'graph.png'}); const html = await page.$eval('svg', svg => { // SVGを画像として表示させるときに必要なため差し込んでいる svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); return svg.outerHTML; }); fs.writeFileSync('graph.svg', html); browser.close(); })();
outerHTML
でSVG要素を含めたHTMLを取得してきています
それをそのままファイルに保存するだけです
余談ですがデバッグ用にpage.on
でコンソールに出てくる内容とhttp通信のログを表示するようにするコールバックを入れましたがこれは結構便利でした
実行
node app.js
SVG部分のみ取得することができるようになりました
はてなブログでsvgを上げることができなかったのですが表示的には画像と同じ見た目です
まとめ
ここまでできればあとは用途によっていろいろできるかなと思います
自分の場合はCircleCIで毎日指標を取ってjsonへ追記、SVG取得させていて
そのSVGをREADMEから読むようにしています
なので毎日自動で数値が更新されていくものをREADMEに行けば読むことができます
(まぁREADMEをそんなに見に行くかというと微妙ですが。。。
他にいい方法ありそうだな感はあるもののこれはこれで面白かったです