Ionic(Angular)アプリのフロントエラーを検知する


AndroidやAppleの開発者コンソールではクラッシュ報告をレポートされますが、発生した具体的なエラー内容は見ることができません。
アプリで密かに発生しているエラーを拾い上げるため、自前のエラーハンドラークラスを作成してエラー情報を送信することが目的です。

フロントエラーの検知方法の考えは、下記記事”失敗談1 : クライアントサイドのエラー調査”を参考にしました。
Qiita - SPAリリースの失敗から学んだこと @norih

環境

  • Ionic4
  • Angular8

Ionic4のプロジェクトで動作検証しましたが、Angularの機能しか使っていないのでAngularでも動作するかと思います。

自前のエラーハンドラークラスを用意する

アプリ内全体でなんらかのエラーが発生した際に動き出すクラスを用意します。
consolole.errorを削除するとコンソールにエラー情報を表示しなくなるので、削除しません。

app-global-error-handler.ts
@Injectable({ providedIn: 'root' })
export class AppGlobalErrorHandler implements ErrorHandler {

  constructor() { }
  handleError(error) {

    console.error(error); // デフォルトのコンソールエラーのため、削除しない。

  }
}

ErrorHandlerの代わりに自前のエラーハンドラークラスを使用する

ErrorHandlerのトークンが呼び出された際に、AppGlobalErrorHandlerのインスタンスを返すように、ルートモジュールのprovidersを修正します。

これでJavaScriptでエラーが発生した際に、AppGlobalErrorHandlerhandleErrorメソッドが動くようになります。

app.modules.ts
@NgModule({
  ...
  providers: [
    ...
    { provide: ErrorHandler, useClass: AppGlobalErrorHandler },
  ],
})

自前のエラーハンドラークラスを実装する

あとはerrorオブジェクトの情報や端末情報などをhttp通信で送信するなど、エラー発生時にやりたいことを実装します。

送信データ例

  • エラースタック
  • エラー発生ページ
  • ユーザ属性
  • 端末のOSとそのバージョン
  • 端末の製造情報
app-global-error.handler.ts
@Injectable({ providedIn: 'root' })
export class AppGlobalErrorHandler implements ErrorHandler {

  constructor(
    private errorLogService: ErrorLogService,
  ) { }
  async handleError(error) {

    console.error(error); // デフォルトのコンソールエラーのため、削除しない。

    const errorLogRequest = new ErrorLogRequest();
    errorLogRequest.message = error.message;

    // ... 他にいろいろな処理を行う

    // エラーログ送信用サービスでエラー情報を送信する
    this.errorLogService.postErrorLog(errorLogRequest)
      .then(request => {
        console.log('success send error log');
      })
      .catch(request => {
        console.log('failed send error log');
      });
  }
}

おわりに

フロントのエラー検知を備えておくと障害時に調査に役立ちますし、開発者が想定しないことが起こっている際に早く気づくことができます。重要な機能だと感じています。

特に利用者のフィードバックが少ないアプリだと積極的にアプリで何が起きているか把握する仕組みが必要です。