IDCF テックブログ

IDCF テックブログ

クラウド・データセンター・ビッグデータを提供するIDCフロンティアの公式テックブログ

フロントエンジニア必見!JavaScriptのエラーログ収集方法

こんにちは、UX開発部の橋口です。

Webサービスを開発するうえで、JavaScriptは絶対的に使われる技術だと思います。
みなさんもJavaScriptでエラーの調査をする際に、クライアントで実行されるためエラーの内容やどこで発生したかが分からなかったり、問い合わせ内容の再現ができず困ったことがあるのではないでしょうか?

解決の糸口を作るためには、クライアントサイドで発生したエラーに関する情報を収集してあげる必要があります。
JavaScriptのエラーログも収集できる著名な製品もありますが、クラウド環境への導入の場合には高額になってしまったり、独自に解析する場合でも、環境などを用意するのも大変ですし管理も大変です。 そこで、今回の記事はトレジャーデータサービス by IDCFにJavaScriptのエラーログを収集する方法について紹介します。

課題

JavaScriptのエラーを収集するにあたり問題になった2つの課題と解決策をご紹介します。

JavaScriptの性質

先ほども挙げましたが、JavaScriptはクライアントサイドで実行されるスクリプトです。
最新のブラウザであればエラー発生時にスタックトレースなど調査時に有益な情報が取得できますが、閲覧してくれる方全員が最新のブラウザを使ってくれるとは限りません。

そのため、古いバージョンであっても、擬似的なスタックトレースが取得できるstacktrace.jsを今回は使用します。

収集にあたって

stacktrace.jsにはJSON形式でエラーの情報をPOSTしてくれるメソッドがありますが、今まで収集してこなかったため実際にどのぐらいのエラーが集まってくるか見当がつかず、収集側にどれだけのキャパシティを用意すべきなのか想定もできません。

そのため、今回は、キャパシティー管理が不要なうえ※1に、後日の解析が容易なトレジャーデータサービス by IDCFにエラーを収集します。
※1 全体で1.5億件、月間1,000万件まではスタータープランに入ります。詳細はこちら

実際に収集してみよう

ここまでは、課題などを上げてきました。
ここからは、実際にトレジャーデータサービス by IDCFへ収集する為の準備をしましょう。

DBの設定

まずはじめに、データベースや、テーブルを作成します。

左上から二番目のDatabasesアイコンをクリックします。

f:id:ynagaoka:20180323164157p:plain

新しいデータベースを作成します。

f:id:ynagaoka:20180323164215p:plain

新しいテーブルを作成します。

f:id:ynagaoka:20180323164225p:plain

writeKeyの取得

javascriptには書き込み専用のwriteKeyをセットします。 しかし、データベースやテーブルごとに制限をかけることができないので専用のアカウントを作成するのがオススメです。 writeKeyはMy profileから確認できます。

画面左下のアイコンをクリックしMy profileをクリックします。

f:id:ynagaoka:20180323164236p:plain

API Keysをクリックします。

f:id:ynagaoka:20180323164249p:plain

認証をするとAPIキーが表示されるのでwriteKeyを控えます。ない場合はCREATEを押して作成しましょう。

f:id:ynagaoka:20180323164258p:plain

サンプルコード

必要な情報が揃ったので実際にエラーログをトレジャーデータサービス by IDCFに送信して見ましょう。

今回はイベントリスナに window.onerror を用いますが、 window.addEventListener を使用することも可能です。
また、スタックトレースの部分を改行で連結しています。 今回はサンプルのためhtmlファイルに直接記載していますが、必要に応じてJavaScriptファイルにすることをおすすめします。

<html>
<head>
  <!-- Treasure Data -->
  <script type="text/javascript">
!function(t,e){if(void 0===e[t]){e[t]=function(){e[t].clients.push(this),this._init=[Array.prototype.slice.call(arguments)]},e[t].clients=[];for(var r=function(t){return function(){return this["_"+t]=this["_"+t]||[],this["_"+t].push(Array.prototype.slice.call(arguments)),this}},s=["addRecord","set","trackEvent","trackPageview","trackClicks","ready","fetchGlobalID","fetchUserSegments"],a=0;a<s.length;a++){var c=s[a];e[t].prototype[c]=r(c)}var n=document.createElement("script");n.type="text/javascript",n.async=!0,n.src=("https:"===document.location.protocol?"https:":"http:")+"//cdn.treasuredata.com/sdk/1.9.2/td.min.js";var i=document.getElementsByTagName("script")[0];i.parentNode.insertBefore(n,i)}}("Treasure",this);
  </script>
  <!-- StackTrace.JS -->
  <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/stacktrace.js/2.0.0/stacktrace.min.js">
  <!-- javascript error collector -->
  <script type="text/javascript">
var td = new Treasure({
  host: 'idcf.in.treasuredata.com',
  // 書き込み専用のwriteKeyを記載します
  writeKey: 'YOUR_WRITE_ONLY_APIKEY_IS_HERE',
  // データベース名を記載します
  database: 'DATABASE_NAME'
});
// Enable cross-domain tracking
// td.set('$global', 'td_global_id', 'td_global_id');
var callback = function(stackframes) {
  return stackframes.map(function(sf) {
    return sf.toString();
  }).join('\n');
};
var errback = function() { return null; };
window.onerror = function(msg, file, line, col, error) {
    // callback is called with an Array[StackFrame]
    var stack = StackTrace.fromError(error).then(callback).catch(errback);
    stack.then(function(stringifiedStack) {
      td.set({
        msg: msg,
        url: file,
        line: line,
        column: col || null,
        stack: stringifiedStack
      });
      // テーブル名を記載します
      td.trackEvent('TABLE_NAME');
    });
};
  </script>
</head>
<body>
  sample
</body>
</html>

実際にエラーログを収集すると、次のようにDB内のテーブルに格納されます。

f:id:ynagaoka:20180323164310p:plain

さいごに

IDCFクラウドでもJavaScriptエラーログを取得中です。
どの画面でどの行でどのようなエラーが発生しているかデータベースに記録されるため、リリース後に新規にエラーが発生していないか、定常的に顧客のUXを低下させるような不具合が発生していないかの確認に役立てています。
改善にとても役立つのでみなさんの作成されるWebアプリケーションでもエラーログの継続的な収集と解析をお勧めいたします。

Copyright © IDC Frontier Inc.