サイトの描画スピードをGoogle PageSpeed Insights APIを使って計測し、Kibanaで可視化する

概要

サイトのリファクタリング前後でページスピードがどれくらい改善されたかを調べるために、 Google PageSpeed Insights APIを使って計測し、さらにKibanaで可視化してみました。

f:id:uggds:20170728175213p:plain

使用技術

  • embulk
  • Google PageSpeed Insights API
  • elasticsearch 5
  • kibana 5

embulk

embulkは、さまざまなデータベース、ストレージ、ファイル形式、およびクラウドサービス間のデータ転送をサポートするオープンソースのバルクデータローダーです。

github.com

pluginが豊富で、今回は以下のpluginを使って実現しました。

一覧サイト
http://whttp://www.embulk.org/docs/ww.embulk.org/plugins/

Page Speed Insights

Page Speed InsightsはURLを指定するだけでサイトのパフォーマンスを診断してくれるGoogleのサービスです。
APIも提供しているので、各種アプリケーションからデータを取得することができます。
APIのガイドはこちら
https://developers.google.com/speed/docs/insights/v2/getting_started

Responseは次のものが返ってきます。

{
 "kind": "pagespeedonline#result",
 "id": "https://developers.google.com/speed/pagespeed/insights/",
 "responseCode": 200,
 "title": "PageSpeed Insights",
 "ruleGroups": {
  "SPEED": {
   "score": 94
  },
  "USABILITY": {
   "score": 100
  }
 },
 "pageStats": {
  "numberResources": 17,
  "numberHosts": 8,
  "totalRequestBytes": "2570",
  "numberStaticResources": 13,
  "htmlResponseBytes": "70113",
  "imageResponseBytes": "14985",
  "javascriptResponseBytes": "709324",
  "numberJsResources": 10
 },
 ...

具体的な秒数ではなく、scoreという形で評価しているところが特徴です。
上記ガイドによると

PageSpeed のスコアの範囲は 0~100 ポイントです。スコアが大きいほど良好で、85 以上のスコアはそのページのパフォーマンスが高いことを示します。

だそうです。

環境準備

KibanaとElastisearch

macVirtualBoxで作ったLinux環境のDockerコンテナ上にElasticsearchとKibanaを構築します。
セットアップ方法下でまとめました。 ugap.hatenablog.com

Page Speed Insights

Googleのサービスになるので、Google Cloud PlatformにログインしてAPIキーを発行してください。

embulk

git cloneで取得します。

$ git clone https://github.com/embulk/embulk.git

embulkのセットアップは公式のreadmeを確認してください。
セットアップが完了したら、pluginをインストールします。

$ embulk gem install embulk-input-http embulk-parser-json embulk-output-elasticseach embulk-filter-add_time embulk-filter-column

config.ymlに記述する例を記載します。

in:
  type: http
  url: https://www.googleapis.com/pagespeedonline/v2/runPagespeed
  params:
    - {name: url, value: '[計測したいサイトのURL]'}
    - {name: key, value: '[取得したAPIキー]'}
  parser:
    type: jsonpath
    root: $
    schema:
      - {name: id, type: string}
      - {name: pageStats, type: json} #---------(1)
      - {name: ruleGroups, type: json} #---------(2)
  method: get
filters:
  - type: add_time #---------(3)
    to_column: {name: created_at, type: timestamp}
    from_value: {mode: upload_time}
  - type: expand_json
    json_column_name: pageStats #---------(4)
    root: "$." #---------(5)
    expanded_columns:
      - {name: numberResources, type: double}
      - {name: totalRequestBytes, type: double}
      - {name: numberStaticResources, type: double}
      - {name: htmlResponseBytes, type: double}
      - {name: cssResponseBytes, type: double}
      - {name: imageResponseBytes, type: double}
      - {name: javascriptResponseBytes, type: double}
      - {name: otherResponseBytes, type: double}
      - {name: numberJsResources, type: double}
      - {name: numberCssResources, type: double}
  - type: expand_json
    json_column_name: ruleGroups
    root: "$.SPEED." #---------(6)
    expanded_columns:
      - {name: score, type: double}
out:
  type: elasticsearch
  nodes:
  - {host: 192.168.33.10, port: 9200}
  index: googleinsights
  index_type: googleinsights
項番 説明
(1) APIの戻り値のうち、jsonオブジェクトであるruleGroups.SPEED.scoreが欲しいため記載する。
(2) APIの戻り値のうち、jsonオブジェクトであるpageStats以下の項目が欲しいため記載する。
(3) 戻り値にtimestampが含まれていないため、embulk-filter-add_timeプラグインを使ってelasticsearchに送る際にtimestampを示すカラムを追加する。
(4) そのままでは扱えないので、embulk-parser-jsonプラグインを使ってパースする。
(5) どこを起点にjsonオブジェクトの値を取得するかを定義する。
pageStats直下のnumberResources等を取得したいため、この設定となる。
(6) ruleGroups.SPEED.scoreを取得するため、この設定となる。

実行

それでは実行します。

1. elasticsearch、kibanaを立ち上げます。
2. embulkを実行します。

$ embulk run config.yml

3. kibanaにアクセスしてみて、Discoverにデータが投入できていれば成功です。 f:id:uggds:20170714194807p:plain 4. Visualizeで可視化してみます。
数時間おきにelasticsearchにデータを投入しておいて、折れ線グラフを作成してみました。

横軸にcreated_atを指定し、縦軸にjavascriptResponseBytesを指定してみます。 f:id:uggds:20170714200924p:plain

うまく可視化することができました。

さらに突っ込んでみる

他にも、cssやimageのResponseBytesが取得できるのですが、それらを足し合わせたResponseBytesはないのが残念です。
そこで、Kibanaの画面上でこれらの項目を足し合わせるscriptを書き、新しい項目としてカラムを追加することをやってみます。

以下のサイトを参考にさせていただきました。
Kibanaでの項目集計について - 日本語による質問・議論はこちら - Discuss the Elastic Stack

サイトにあったやりかたと同様に
Kibana > Management > scripted fields > Add Scripted Field
からscriptを作成します。

f:id:uggds:20170714202313p:plain

作成したスクリプトは以下になります。

def t = [];
if (doc['cssResponseBytes'].value != null) {
  t.add(doc['cssResponseBytes'].value);
}
if (doc['htmlResponseBytes'].value != null) {
  t.add(doc['htmlResponseBytes'].value);
}
if (doc['imageResponseBytes'].value != null) {
  t.add(doc['imageResponseBytes'].value);
}
if (doc['otherResponseBytes'].value != null) {
  t.add(doc['otherResponseBytes'].value);
}
if (doc['javascriptResponseBytes'].value != null) {
  t.add(doc['javascriptResponseBytes'].value);
}

return t;

それぞれの値を配列に格納し、それをtotalResponseBytesというフィールドに集め、可視化するときに縦軸のAggregationでsumを指定することになります。

f:id:uggds:20170714203849p:plain

javaScriptのResponseBytesが全体のほとんどを占めていて、絵的には変わっていないように見えますが、 横軸をみるとうまく足し合わせたものになっているようです。

まとめ

今回はサイトの速度を可視化するため、Google PageSpeed Insights APIを使用しましたが、 embulkとelasticsearchの連携は他にも応用がききそうなので、他のデータも可視化して楽しめそうです!