エラー検知・監視ツールのSentryをAngularで試してみた

2021.04.09

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは!DA(データアナリティクス)事業本部 インテグレーション部の大高です。

フロントエンドで利用できるエラー検知・監視ツールとして、SentryというSaaSのツールがあります。

様々なプラットフォームに対応しており、2021/04現在では、93のプラットフォームに対応しているようです。

最近、Sentryが良いという話を聞いたので、実際にAngularでどのように利用できそうかを試してみました。

なお、Lambdaで試した記事が既にありますので、Lambdaの場合にはこちらが参考になるかと思います。今回、わたしは単純にAngularで試してみた部分についてだけ書いていきたいと思います。

前提条件

nodeのバージョンはv14.16.0を利用しています。また、パッケージ管理にはyarnを利用しています。

Angular CLIは11.2.8を導入済みです。

サンプルプロジェクトの準備

今回Sentryを試すにあたって、サンプルのプロジェクトを以下からお借りしました。

こちらはAngularの有名な公式チュートリアル「Tour of Heroes」のサンプルプロジェクトです。まずはこちらをcloneしてセットアップしておきます。

$ git clone https://github.com/johnpapa/heroes-angular.git
$ cd heroes-angular
$ yarn install
# このままだとtypescriptのバージョンエラーが起きるので以下でバージョン指定インストール
$ yarn add --dev typescript@4.0.5

これでサンプルがプロジェクトが起動できるようになりました。

$ ng serve

Sentryの設定

Sign upページからアカウントを作成して利用を開始します。

アカウントができてログインすると、まずはQuick Startが始まるので、これに沿って設定をしていきます。

Create a new Project

まずはプラットフォームの選択です。こちらは「ANGULAR」を選択します。

Configure Angular

必要なパッケージをインストールします。これは特に問題ないですね。

$ yarn add @sentry/angular @sentry/tracing

次に、初期化処理の追記です。用意したサンプルプロジェクトに対して修正していきます。

src/main.ts

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import * as Sentry from "@sentry/angular";
import { Integrations } from "@sentry/tracing";

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

Sentry.init({
  dsn: "https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.ingest.sentry.io/xxxxxxx",
  integrations: [
    new Integrations.BrowserTracing({
      tracingOrigins: ["localhost", "https://yourserver.io/api"],
      routingInstrumentation: Sentry.routingInstrumentation,
    }),
  ],

  // Set tracesSampleRate to 1.0 to capture 100%
  // of transactions for performance monitoring.
  // We recommend adjusting this value in production
  tracesSampleRate: 1.0,
});

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

dsnはSentryプロジェクト固有のものですね。これは実際にプロジェクトで利用する際にはenvironment.tsに移したほうが良さそうです。

また、tracingOriginsで指定しているlocalhosthttps://yourserver.io/apiが気になりますが、以下に記載がありました。

下記の例示の箇所が分かりやすいですね。

For example:

  • A frontend application is served from example.com
  • A backend service is served from api.example.com
  • The frontend application makes API calls to the backend
  • Therefore, the option needs to be configured like this: new Integrations.BrowserTracing({tracingOrigins: ['api.example.com']})
  • Now outgoing XHR/fetch requests to api.example.com will get the sentry-trace header attached

ここに指定することにより、sentry-traceヘッダがバックエンドサービスへのAPIコール時に付与されるとのことです。また、場合によってはCORSの設定も必要になるようなので要注意ですね。

今回はとりあえずそのままにしておきます。

ErrorHandler and Tracer

続いて、エラーハンドリングの設定を追加します。

src/main.ts

import { BrowserModule } from '@angular/platform-browser';
import { APP_INITIALIZER, ErrorHandler, NgModule } from "@angular/core";
import { HttpClientModule } from '@angular/common/http';
import { Router } from "@angular/router";
import * as Sentry from "@sentry/angular";

import { routes } from './router';
import { AppComponent } from './app.component';
import { AppStoreModule } from './store/store.module';
import { AboutComponent } from './about.component';
import { RouterModule } from '@angular/router';
import { externalModules } from './build-specific';
import { declarations } from './core';

@NgModule({
  declarations: [AppComponent, AboutComponent, declarations],
  imports: [
    BrowserModule,
    HttpClientModule,
    RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' }),
    AppStoreModule,
    externalModules
  ],
  bootstrap: [AppComponent],
  providers: [
    {
      provide: ErrorHandler,
      useValue: Sentry.createErrorHandler({
        showDialog: true,
      }),
    },
    {
      provide: Sentry.TraceService,
      deps: [Router],
    },
    {
      provide: APP_INITIALIZER,
      useFactory: () => () => {},
      deps: [Sentry.TraceService],
      multi: true,
    },
  ],
})
export class AppModule {}

エラー発生箇所を仕込む

最後に、このままだとエラーは起きないのでエラー発生箇所を仕込んでおきます。

下記画面でのHeroes追加時の「Save」ボタンクリック時にエラーが起きるようにします。

該当箇所は以下になるので、Exceptionを発生するように修正しておきます。

src/app/heroes/hero-detail.component.ts

  saveHero() {
    throw new Error('sentry error testing.');
    this.save.emit(this.editingHero);
    this.clear();
  }

いざ、エラー検知

では、アプリを動かして該当ボタンをクリックしてみましょう。

クリックすると、クラッシュレポートダイアログが表示されました!

せっかくなので、クラッシュレポートを入力して送信しておきます。

Sentryの画面で確認する

では、Sentryの管理画面で該当エラーを確認してみます。プロジェクトを開くとエラーが通知されているのがわかります。

エラーを開くとこのような感じで表示されます。クライアントのOSやブラウザの情報、IPアドレスやエラー発生時のURLまで、バッチリと取得されていますね。先程送信したクラッシュレポートも出ています。

下にスクロールすると、エラー発生時のスタックトレースやBreadcrumbs(パンくず)も確認できます。ユーザが直前までしていた操作がバッチリ出ているので、エラーの再現確認などでとても役立ちそうです。

クラッシュレポートについては、別タブでまとめて確認することもできます。

まとめ

以上、エラー検知・監視ツールのSentryをAngularで試してみました。

今回は軽く触っただけですが、感触としてはとても良いと思いました。特に以下の点がとても良いなと感じました。

  • アプリのクラッシュ時に、クライアントサイドにクラッシュレポートのダイアログが表示される。
  • Sentryの管理画面でクライアントの環境情報が詳細に確認できる。
  • 例外発生時のスタックトレースが確認できる。
  • クラッシュするまでのユーザー操作が「BREADCRUMBS」として表示されるので、エラー発生までのユーザー操作フローが追いやすい。

無料のDeveloperプランでも5,000エラーまではハンドリングできますし、まずは試しに導入して、エラー数の上限緩和やメトリクスアラートなどの上位プランのみの機能を利用したくなってきたらプランを上げていく感じで良いのかなと思いました。

どなたかのお役に立てば幸いです。それでは!