JavaScript
error
Web

ユーザのブラウザで起きた JavaScript のエラーを収集する

なぜエラーを収集するのか

  • バグ探し
    • バグを見つけて潰していくため
  • ユーザからのバグ報告の補助
    • ユーザに報告の負担をかけないため

エラーを取得する

取得タイミング

  • window.onerror
  • Promise のエラー
  • フレームワーク毎の特定のタイミング

window.onerror

window.onerror にメソッドを登録しておくことでエラー発生時にそのメソッドが呼ばれる。try-catch でハンドリングしていないエラーが流れてくる。

window.onerror = (message, file, lineNo, colNo, error) => {
}

古いブラウザでは error オブジェクトが取得できないので注意すること。

Promise のエラー

window.onerror では Promise が reject された際のエラーハンドリングを行っていないエラーは検出できません。

つまり以下のようなコードでは反応してくれないということです。

window.onerror = (a,b,c,d,e) => {
  console.error('window.onerror', a,b,c,d,e);
};

const promise = new Promise(() => {
  throw new Error('error dayo~');
});
promise.then(() => {
  console.log('kurae!');
});

そこで登場するのが unhandledrejection イベントです。

window.addEventListener("unhandledrejection", function (event) {
  console.warn("WARNING: Unhandled promise rejection. Shame on you! Reason: "
               + event.reason);
});

2018/03/09 現在主要ブラウザでは Chrome と Safari のみこのイベントに対応しています。

フレームワーク毎の特定のタイミング

使用しているフレームワークによっては window.onerror でエラーを取得できない場合がある。例えば Angular では ErrorHandler として実装する必要がある。
Sentry のサイト を見ると各フレームワークでの雰囲気が掴める。

取得する情報

  • スタックトレース
  • UserAgent
  • URL
  • 現象が起きたページ ID
    • URL を割り振っていない場合とか
  • ユーザ情報
    • 無名化
  • その他有るとバグの特定に便利なものを見つけたら教えてください

stacktrace.js

window.onerror で取得したエラー情報をそのまま文字列で送ってもいいけどライブラリを使うともっと扱いやすい。
stacktrace.js を使うと sourcemap を解釈してくれるので大変便利。
sourcemap ファイルを非公開にしている場合は Sentry 等の仕組みに乗るか stacktrace.js 以外を検討する必要あり。

エラーを収集する

収集先の選別

  • エラー収集系サービス
    • 一覧
    • 大抵 window.onerror でなく個別の仕組みが用意されている
    • 既に使ってるサービスがあればそこに JavaScript のエラーも投げつけると良さそう
  • 自前サーバ
    • Ajax でエラー内容を送りつける

自前サーバに投げるときの注意点

別ドメインにある JavaScript ファイルを読み込んでいる場合 CORS を突破する必要がある。
さもないとエラー内容が全て Script error. に置き換わってしまう。とても悲しい。

対応しないといけないのは以下の2つ。

  • crossorigin 属性
  • CORS ヘッダ

crossorigin 属性

スクリプトを読み込んでいる箇所に crossorigin="anonymous" を付与する。

<script src="http://another-domain.com/app.js" crossorigin="anonymous"></script>

CORS ヘッダ

JavaScript ファイルを提供するサーバのレスポンスに Access-Control-Allow-Origin ヘッダを付与する。