Sentry sourcemapの導入とエラーハンドリング

みなさんこんにちはraraya99です。 前回のSentry導入記事の続編です。 blog.ingage.jp

はじめに

前回の記事では、Sentryを導入するまでの方法を紹介しました。今回はSourcemapの導入とエラーハンドリングに焦点を当てます。 Sentryでエラー検知した際、Sourcemapがあるとエラー箇所の特定が容易に行なえます。 また、エラーハンドリングすることによって重要なエラーが不要なエラーに埋もれないようにすることができます。

目次

1. 前提条件

  • Node.jsとnpmがインストールされている
  • Vue.jsプロジェクトが既に存在する
  • Sentryアカウントが既に存在する
  • ビルドツールとしてViteを使用している

2. Sourcemapの導入

2.1. Sourcemapとは

Sourcemapとは、開発者が書いた元のソースコードと、ブラウザで実行される変換後のコード(例えば、圧縮やトランスパイルされたコード)とを関連付けるためのデータで、開発者がデバッグを行いやすくするための技術です。

具体的には、Sourcemapは以下のような役割を果たします

①コードマッピング

トランスパイルされたコード(例えば、BabelによってES6からES5へ変換されたJavaScriptコード)や、圧縮されたコード(例えば、minifyされたCSSやJavaScript)は元のソースコードとは異なる形で表示されます。 Sourcemapを使うと、ブラウザの開発者ツールで変換後のコードではなく、元のソースコードを直接見ることができます。

②デバッグの容易化

トランスパイルや圧縮によって変換されたコードは、元のコードとは異なる構造を持っているためデバッグが困難になります。 Sourcemapを利用することで、元のコード上でブレークポイントを設定したり、変数を追跡したりすることができ、デバッグ作業が容易になります。

③エラートラッキング

本番環境でのエラーを追跡する際にもSourcemapが役立ちます。 エラーが発生した際にトランスパイルされたコードの行番号だけでなく、元のソースコードの対応する行番号を知ることができます。

2.2. Sourcemapの導入方法

基本的には公式ドキュメントを参考に docs.sentry.io

バージョン管理の方法 release.nameにバージョンを指定すると補足したエラーがどのバージョンで発生したかわかります。 '20231101'など文字を直接していすることもできます。環境変数を指定することにより様々な値を登録することができます。 弊社ではエラーがどのBuildで起こったのか調査しやすくするため、codeBuildのビルドIDを指定しております。

    sentryVitePlugin({
      org: "組織名",
      project: "プロジェクト名",
      authToken: process.env.TOKEN,
      'release': {
        name: process.env.BUILD_ID, // codebuildのビルドID,
        deploy: {
          env,
        },
      },
    }),

2.3. Sourcemap導入した結果

下記のようにエラー箇所がわかりやすくなり、Sentryでエラー調査する際のハードルが一気に下がります!

sourcemap before after

*画像は公式サイトのものです。 Source Maps for Browser JavaScript | Sentry Documentation

3. エラーハンドリング

3.1. エラーハンドリングとは

はじめにでも記述したとおり、重要なエラーが不要なエラーに埋もれないようにすることができます。 また、プランごとに1ヶ月間に送信できるエラー数の上限 があるため不要なエラーを送信しないようにする必要があります。 いつの間にか大量のエラーによって上限に達してしまうことがあります。(私も何度かやらかしました..) 上限に達すると次月までエラーが破棄されます..

3.2. エラーハンドリングするとどうなる

不要なエラーがなくなり、重要なエラーに集中してとりかかることができます。 不要なエラーが多いと通知が頻繁に来て業務に支障があるのと、オオカミエラーとなって誰も気にしなくなってしまいます。

3.3. エラーハンドリングの方法

様々な設定値を記述するsentryPlugin.tsのSentry.initに記述します。 詳細は前回記事参照 フロントエンドにSentryを導入する - インゲージ開発者ブログ

①beforeSend

Sentryにエラー送信をする前に様々なチェックを挟むことができます。 弊社ではエラー量の6割近くが第三者ライブラリからのエラーだったため除外することとしました。 そのため、スタックトレースにvuetifyvendorが含まれていたら除外するようにしました。 vuetifyはCSSフレームワークのvuetifyのエラーで、vendorは外部ライブラリや依存モジュールが格納されるディレクトリです。 エラー量の多くを占めているのが利用者が古いバージョンのブラウザを利用しているケースです。 ライブラリで使用しているArray.prototype.at()をブラウザがサポートしていないなど、、古いブラウザを使用している方へ更新を促す対応が必要そうです。

詳細は公式ドキュメント参照 Filtering for Browser JavaScript | Sentry Documentation

②ignoreErrors

エラーのメッセージを指定しエラーを無視できます。正規表現も可能です。 Network Errorはバックエンド側のSentryで補足するため除外しました。

Sentry.init({
      Vue:         app,
      dsn:         'https://xxxxxx',
      environment: env,
      beforeSend(event) {
        // スタックトレースに含まれていたら無視するパス
        const ignorePaths = [
          'vuetify',
          'vendor',
        ];
        if (event.exception) {
          try {
            const shouldIgnoreError = event.exception.values?.some((value) => {
              return value.stacktrace?.frames?.some((frame) => {
                return ignorePaths.some((path) => {
                  return frame.filename?.includes(path);
                });
              });
            });

            if (shouldIgnoreError) return null;
          }
          catch (err) {
            return event;
          }
        }
        // 例外ではないイベントはそのまま通す
        return event;
      },
      ignoreErrors: [
        'Network Error',
      ],
    });

4. まとめ

不要なエラーを取得しないようになり、重要なエラーが埋もれず気づきやすくなりました!また、エラーの上限数に達する危険性も格段に減りゆとりを持てるようになりました。それでも新機能開発などで新しいエラーが大量に発生する可能性もあるため、安心はできません。 バックエンド側とエラーの上限数をシェアしており、フロントエンド側だけで上限数を使い切るわけにもいかないため更にエラーハンドリングの勉強を進めて最適化を図りたいです。