Google Analytics の サイトの速度指標を javascript timing api で 再現する
で、Google Analytics の速度指標を計算するJavascript を書きました。
こちらをSelenium - Web Browser Automation から実行する形にしようかと思っていたのですが、sitespeedio/browsertime: Your browser, your page, your scripts! でも同様のことが、且つ CUI で実現可能でしたので、こちらをインストールして、スクリプトを実行するようにしてみます。


参考


前提

以下の環境で作業は実施しています。

  • OS

    % sw_vers 
    ProductName:    Mac OS X
    ProductVersion: 10.12.6
    BuildVersion:   16G29
    

  • DockerのVersion

    % docker version
    Client:
     Version:      17.06.2-ce
     API version:  1.30
     Go version:   go1.8.3
     Git commit:   cec0b72
     Built:        Tue Sep  5 20:12:06 2017
     OS/Arch:      darwin/amd64
    
    Server:
     Version:      17.06.2-ce
     API version:  1.30 (minimum version 1.12)
     Go version:   go1.8.3
     Git commit:   cec0b72
     Built:        Tue Sep  5 19:59:19 2017
     OS/Arch:      linux/amd64
     Experimental: true
    


そもそも Browsertime とは

Documentation sitespeed.io 5.x Brower メトリクス取得に使用されているツールで、単独実行だと Brower のメトリクスのみを取得できます。

Browsertime以下のできることが記載されています。

  1. Navigation Timing と、User TimingResource TimingRUM Speed Index(Resource Timing API から Speed Index指標を頑張って算出する) をブラウザから直接取得できる。

  2. ブラウザアクセス時のHARファイルを生成できる。
    HARファイルが何かよくわかっておらず、以下が参考になりました。
    Firefox の Firebug や Chrome のデベロッパーツールの Network の結果を HAR にエクスポートしたり PDF に印刷する方法 | ウェブル

  3. ブラウザでカスタムJavascriptが実行できる。
    やりたいのはこれです。

  4. 動画を記録し、結果を分析できる。

CUIからいろいろできると、スケジューラに仕込んで実行できるので、非常に助かります。
ブラウザ自動操作 とか 2010年代前半に触ったきりでしたが、頗る進歩しております。


Browsertimeを実行する

Browsertime記載を参考に、コマンドを実行していきます。
コマンド は、MACにインストールした Docker 上で実行します。

https://www.sitespeed.io/ メトリクスを取得する

  • ** コマンドを実行**

    docker run --shm-size=1g --rm -v "$(pwd)":/browsertime-results sitespeedio/browsertime --video --speedIndex https://www.sitespeed.io/
    

  • ** OUTPUT**
    以下のエラーが発生しました。

    17:55:03.581 - No video frames found in /browsertime-results/www.sitespeed.io/2017-09-08T175442+0000/video/images/0
    
        at Promise.all.then.arr (/usr/src/app/node_modules/execa/index.js:208:11)
        at process._tickCallback (internal/process/next_tick.js:109:7)
    From previous event:
        at /usr/src/app/node_modules/mkdirp/index.js:30:20
        at FSReqWrap.oncomplete (fs.js:123:15)
    From previous event:
        at Object.run (/usr/src/app/lib/support/video/scripts/runVisualMetrics.js:13:8)
        at Promise.mapSeries.postScript (/usr/src/app/lib/core/engine.js:360:24)
    From previous event:
        at Promise.resolve.tap.tap.tap.tap.tap.tap.tap.tap.tap.tap.results (/usr/src/app/lib/core/engine.js:359:19)
    From previous event:
        at runIteration (/usr/src/app/lib/core/engine.js:358:10)
        at Promise.reduce (/usr/src/app/lib/core/engine.js:405:27)
    From previous event:
        at Promise.resolve.tap.tap.tap.tap.result (/usr/src/app/lib/core/engine.js:402:17)
        at runCallback (timers.js:672:20)
        at tryOnImmediate (timers.js:645:5)
        at processImmediate [as _immediateCallback] (timers.js:617:5)
    From previous event:
        at Engine.run (/usr/src/app/lib/core/engine.js:401:8)
        at /usr/src/app/bin/browsertime.js:63:21
    From previous event:
        at run (/usr/src/app/bin/browsertime.js:62:6)
        at Object.<anonymous> (/usr/src/app/bin/browsertime.js:137:1)
        at Module._compile (module.js:570:32)
        at Object.Module._extensions..js (module.js:579:10)
        at Module.load (module.js:487:32)
        at tryModuleLoad (module.js:446:12)
        at Function.Module._load (module.js:438:3)
        at Module.runMain (module.js:604:10)
        at run (bootstrap_node.js:389:7)
        at startup (bootstrap_node.js:149:9)
        at bootstrap_node.js:504:3
    

対処方法がよくわからず、対象サイト変えて再度実行します。

https://www.yahoo.comメトリクスを取得する

  • ** コマンドを実行**
    browsertimeで、Webページの描画過程を録画する - togatttiのエンジニアメモ記載されているコマンドを拝借して、https://www.yahoo.comメトリクスを取得します。

    docker run --privileged --shm-size=1g --rm -v "$(pwd)":/browsertime-results sitespeedio/browsertime -n 1 -c cable --video --speedIndex 'https://www.yahoo.com'
    

  • ** OUTPUT**

    Google Chrome 60.0.3112.78 
    Mozilla Firefox 54.0
    [2017-09-08 18:12:29] Running chrome for url: https://www.yahoo.com
    [2017-09-08 18:12:29] sudo tc qdisc add dev eth0 root netem delay 28ms loss 0% rate 5000kbps
    [2017-09-08 18:12:29] Testing url https://www.yahoo.com run 1
    [2017-09-08 18:13:26] 153 requests, 1599.72 kb, backEndTime: 763ms, firstPaint: 1.84s, firstVisualChange: 2.62s, DOMContentLoaded: 5.41s, Load: 8.97s, speedIndex: 5396, visualComplete85: 8.42s, lastVisualChange: 11.07s, rumSpeedIndex: 2790
    [2017-09-08 18:13:27] Wrote data to browsertime-results/www.yahoo.com/2017-09-08T181228+0000
    [2017-09-08 18:13:27] sudo tc qdisc del dev eth0 root
    
    よくわかりませんが、正常終了しました。

https://www.sitespeed.io/ メトリクスを再取得する

  • コマンドを再実行
    もう1度コマンドを実行してみます。

    docker run --shm-size=1g --rm -v "$(pwd)":/browsertime-results sitespeedio/browsertime --video --speedIndex https://www.sitespeed.io/
    

  • OUTPUT

    Google Chrome 60.0.3112.78 
    Mozilla Firefox 54.0
    [2017-09-08 18:16:43] Running chrome for url: https://www.sitespeed.io/
    [2017-09-08 18:16:43] Testing url https://www.sitespeed.io/ run 1
    [2017-09-08 18:16:55] Testing url https://www.sitespeed.io/ run 2
    [2017-09-08 18:17:06] Testing url https://www.sitespeed.io/ run 3
    [2017-09-08 18:17:16] 10 requests, 96.46 kb, backEndTime: 114ms (±9.67ms), firstPaint: 181ms (±10.91ms), firstVisualChange: 250ms (±17.90ms), DOMContentLoaded: 140ms (±12.38ms), Load: 229ms (±9.13ms), speedIndex: 258 (±14.80), visualComplete85: 261ms (±14.06ms), lastVisualChange: 284ms (±11.79ms), rumSpeedIndex: 191 (±9.42) (3 runs)
    [2017-09-08 18:17:16] Wrote data to browsertime-results/www.sitespeed.io/2017-09-08T181642+0000
    
    1回目の失敗が謎ですが、2回目は成功しました。

  • 出力ファイル
    tree コマンドが無い環境で tree コマンドを実現 - Qiita からコマンドは拝借しました。
    動画と、speedindex の測定結果 browsertime.json harファイル browsertime.har出力されています。

    % find www.sitespeed.io/ | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/|  /g'
    www.sitespeed.io|  |--.DS_Store
    www.sitespeed.io|  |--2017-09-08T181642+0000
    www.sitespeed.io|  |  |--browsertime.har
    www.sitespeed.io|  |  |--browsertime.json
    www.sitespeed.io|  |  |--video
    www.sitespeed.io|  |  |  |--0.mp4
    www.sitespeed.io|  |  |  |--1.mp4
    www.sitespeed.io|  |  |  |--2.mp4
    www.sitespeed.io|  |  |  |--images
    www.sitespeed.io|  |  |  |  |--0
    www.sitespeed.io|  |  |  |  |  |--ms_000000.jpg
    www.sitespeed.io|  |  |  |  |  |--ms_000300.jpg
    www.sitespeed.io|  |  |  |  |  |--ms_000317.jpg
    www.sitespeed.io|  |  |  |  |--1
    www.sitespeed.io|  |  |  |  |  |--ms_000000.jpg
    www.sitespeed.io|  |  |  |  |  |--ms_000217.jpg
    www.sitespeed.io|  |  |  |  |  |--ms_000234.jpg
    www.sitespeed.io|  |  |  |  |  |--ms_000250.jpg
    www.sitespeed.io|  |  |  |  |  |--ms_000267.jpg
    www.sitespeed.io|  |  |  |  |--2
    www.sitespeed.io|  |  |  |  |  |--ms_000000.jpg
    www.sitespeed.io|  |  |  |  |  |--ms_000234.jpg
    www.sitespeed.io|  |  |  |  |  |--ms_000250.jpg
    www.sitespeed.io|  |  |  |  |  |--ms_000267.jpg
    


カスタム javascript を実行する

自サイト対してカスタム javascript を指定して、browsertime を実行します。

実行するスクリプト

browsertime/browserscripts/timings at master · sitespeedio/browsertime
参考に以下作成しました。
Google Analytics の速度指標を あらかじめ計算して出力するスクリプトです。

  • MyCustomScript.js
    (function() {
    
        var perfData = window.performance.timing;
    
        var jsonObject = {
            "backEnd" : { 
                "pageLoadTime" : perfData.fetchStart - perfData.navigationStart,
                "redirectionTime" : perfData.redirectEnd - perfData.redirectStart,
                "domainLookupTime" : perfData.domainLookupEnd - perfData.domainLookupStart,  
                "serverConnectionTime" : perfData.connectEnd - perfData.connectStart,  
                "serverResponseTime" : perfData.responseStart - perfData.requestStart,
                "pageDownloadTime" : perfData.responseEnd - perfData.responseStart
            },
            "frontEnd": { 
                "pageLoadTime" : perfData.fetchStart - perfData.navigationStart,
                "domInteractiveTime" : perfData.domComplete - perfData.domInteractive,
                "domContentLoadedTime" : perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart
            }
        };
        return jsonObject;
    })();       
    

コマンドを実行

  • コマンド

    docker run --shm-size=1g --rm -v "$(pwd)":/browsertime-results sitespeedio/browsertime \
    --skipHar \
    --script /browsertime-results/MyCustomScript.js \
    --prettyPrint \
    -n 5 \
    --speedIndex https://www.monotalk.xyz
    
    以下指定オプションについて説明します。
    sitespeedio/browsertime: Your browser, your page, your scripts!指定可能なオプションは記載されています。

  • –skipHar
    harファイルを取得しないようにします。

  • –script /browsertime-results/MyCustomScript.js
    customスクリプトファイルを指定します。
    -v "$(pwd)":/browsertime-resultsホストのカレントディレクトリをコンテナの/browsertime-resultsマウントしていますので、MyCustomScript.jsカレントディレクトリに配置します。

  • –prettyPrint
    browsertime.json整形して出力します。

  • -n 5
    メトリクス取得回数を指定します。この場合5回です。

  • –speedIndex
    スピードインデックスメトリクスを取得します。
    指定しない場合はデフォルトでこれが効いていそうに思います。

  • OUTPUT
    取得指定した覚えのないjpg出力されております。
    browsertime.json取得できていますので、内容を確認します。

    % find www.monotalk.xyz/ | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/|  /g'
    www.monotalk.xyz|  |--2017-09-09T031247+0000
    www.monotalk.xyz|  |  |--browsertime.json
    www.monotalk.xyz|  |  |--video
    www.monotalk.xyz|  |  |  |--images
    www.monotalk.xyz|  |  |  |  |--0
    www.monotalk.xyz|  |  |  |  |  |--ms_000000.jpg
    .....
    www.monotalk.xyz|  |  |  |  |--1
    www.monotalk.xyz|  |  |  |  |  |--ms_000000.jpg
    .....
    www.monotalk.xyz|  |  |  |  |--2
    www.monotalk.xyz|  |  |  |  |  |--ms_000000.jpg
    .....
    www.monotalk.xyz|  |  |  |  |--3
    www.monotalk.xyz|  |  |  |  |  |--ms_000000.jpg
    .....
    www.monotalk.xyz|  |  |  |  |--4
    www.monotalk.xyz|  |  |  |  |  |--ms_000000.jpg
    .....
    

browsertime.jsonの抜粋

以下、browsertime.json抜粋です。customプロパティが実行したfunctionの戻りが記録されます。
5回記録していたため、以下は5回出力されています。

  "custom": {
    "MyCustomScript": {
      "backEnd": {
        "domainLookupTime": 0,
        "pageDownloadTime": 8,
        "pageLoadTime": 108,
        "redirectionTime": 0,
        "serverConnectionTime": 45,
        "serverResponseTime": 4209
      },
      "frontEnd": {
        "domContentLoadedTime": 3,
        "domInteractiveTime": 1740,
        "pageLoadTime": 108
      }
    }
  }


まとめ

以下まとめます。

  • sitespeed.io は、browsertime を内部で使用しており、browsertime単独でも実行できる

  • browsertime には、カスタム指標を取得するスクリプトが登録でき、custom プロパティに出力される。
    sitespeed.ioは、内部でbrowsertimeを使用しているため、sitespeed.ioでも同様のことができる。

  • 出力形式はjsonのみ、htmlレポートはsitespeed.ioの機能で出力する必要がある。

単独だと、json形式での出力のみ可能で、日々実行してメトリクスを取得する場合は、別途スクリプト書いて取り込みが必要になりそうです。
sitespeed.ioだとそのあたりをカバーしてくれるので、日々の実行にはそちらを使いそうです。
スポットでパフォーマンス計測する場合等は、動画も取得できるので用途としてはそれかなと思いました。

以上です。

コメント