2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

フロントエンドのSentryを実運用に持ち込むためにやったことメモ

Last updated at Posted at 2025-06-04

背景

弊社ではフロントエンドのエラートラッキングにSentryを導入していたのですが、ほとんど運用されていませんでした。
フロントエンドで重大なエラーが発生することは稀であり、エラー調査においてSentryが必須な場面がほとんどなかったためです。

ただし、小さなバグやユーザーからの問い合わせは定期的に発生しており、その調査を行う際にSentryがあった方が便利だと感じる場面は多々ありました。

そのため、Sentryを適切に活用しようと思ったのですが、現状を整理したところ以下の課題がありました。

  • SourceMapsがなく、エラー箇所のコードが読みにくい
  • エラーが解決されずに放置され、Issueに大量に溜まっている
  • 頻繁に発生するエラーがクォーターを多く消費する
  • ユーザーがら問い合わせがあった際に、エラーの再現が難しい(これは可能であれば改善したい課題)

上記の課題を解決するために調査・実施したことを紹介します。

動作環境

1. SourceMapsの導入

nuxi generate時に、SourceMapsを生成するようにします

nuxt.config.ts
  sourcemap: {
    server: true,
    client: true
  }

assetsにビルドしたコードと生成したSourceMapのディレクトリのパスを指定します。
filesToDeleteAfterUploadを指定することで、Sentry送信後にSourceMapsを削除します。これにより、SourceMapsがホスティングされて外部に公開されるのを防ぎます。

nuxt.config.ts
plugins: [
  sentryVitePlugin({
    sourcemaps: {
      assets: [
        '.nuxt/dist/client/_nuxt/*.js',
        '.nuxt/dist/client/_nuxt/*.js.map'
      ],
      filesToDeleteAfterUpload: [
        '.nuxt/dist/client/_nuxt/*.js.map',
      ],
    }
  })
]

ただ、弊社の環境ではfilesToDeleteAfterUploadを使用してもSourceMapsが削除されなかったので、CI上でホスティング前にSourceMapsを削除する処理を追加しました。

SourceMapsの導入することでコードの可読性が上がり、エラー調査がやりやすくなりました。

エラーの整理

大量に溜まっているエラーを整理するために、以下を実施しました。

  • エラー内容を確認し、恒久的に発生しないよう修正する
  • エラーの修正が難しい場合
    • 重要度の低いエラーや発生頻度の低いエラーはPriorityを下げるか、一旦アーカイブする
    • ノイズになる場合や発生頻度が高くクォーターを大量消費する場合は、Sentryに送信しないようにする
      • ライブラリ内で発生した例外は原因の特定が難しく、かつノイズになるので送信しないようにしました
      • 4xx系のエラーやネットワークエラーはノイズになるため、送信しないようにしました

エラーを恒久的に発生させないようにするのが最も良いので、1つ1つのバグを潰すような作業を1-2ヶ月かけて実施しました。
null(undefined)の値をメソッドチェーンで参照しようとして発生したエラーが多い印象でした。再現が難しく解決に時間を要するものもありました。

エラーを送信しないようにする方法

Sentryでエラーを送信しないようにする方法は2つあります。

弊社はチームプランなので、エラー送信前にフィルタリングする方法を採用しました。

送信前のエラーに対して操作できるbeforeSend関数

第一引数がevent、第二引数がhintです。eventとhintの2つの引数があり、それぞれエラーやイベントなどの情報が入っています。
beforeSendを使って、送信前にエラーオブジェクトに対して操作できます(以下のコードは公式ドキュメントより引用

Sentry.init({
  dsn: "https://1e30cec9a9124eb6a66f70a799cee948@o360365.ingest.us.sentry.io/3631418",

  // Called for message and error events
  beforeSend(event) {
    // Modify or drop the event here
    if (event.user) {
      // Don't send user's email address
      delete event.user.email;
    }
    return event;
  },
});

エラーを送信しないようにするためには、beforeSendの戻り値をnullにします。

Sentry.init({
  dsn: "https://1e30cec9a9124eb6a66f70a799cee948@o360365.ingest.us.sentry.io/3631418",

  // Called for message and error events
  beforeSend(event) {
    // Modify or drop the event here
    if (event.user) {
      // Don't send user's email address
      delete event.user.email;
    }
    return null;
  },
});

beforeSendを使用して、特定のエラーのみ送信しないようにすることが可能です。
例えば、ノイズになるため4xx系のエラーやネットワークエラーは送信しないようにしました。

Sentry管理画面から見ることのできる情報

Issue一覧画面Issue詳細画面をよく使用します

Issue

エラーはIssueと呼ばれます。Sentry管理画面のIssues画面から確認できます。
ステータスについては、Issueのステータス一覧に詳しい説明が記載されています。

新しいエラーが発生するとUnresolvedでIssueが作成されます。エラーを修正した場合は画面からResolvedにステータスを変更します。

緊急性が低いもの、またはノイズになるエラーはArchivedに変更します。Archivedにするとアラートを停止します。短時間に大量のエラーが発生するとEscalatingになります。

Issueを完全に削除した場合は、同様のエラーが再発すると新しいエラー扱いになります。

Issue Grouping

Sentryはエラーの類似性を評価し、同様のエラーを同じIssueにグルーピングしています。

fingerprintstack traceexceptionmessageの順でグルーピングに使用されます。後者に行くほどグルーピング精度は下がります。

どの方ほグルーピングされたかは、Issue詳細ページの一番下で確認できます。

Activity

Issueに対してコメント可能です。

Environments

環境tagを設定し、どの環境で発生したエラーか区別できます。

SDK初期化時に設定します。

Releases

ソースコードにバージョンをつけることができます。

どのバージョンのソースコードで発生したエラーか区別できます。

Session Replay

Session Replayを導入すると、ユーザーの行動(画面録画、ネットワークリクエスト、DOMイベントやコンソールログ)を記録し再生することができます。

エラーを手元で再現しやすくしたり、ユーザーが操作に戸惑っている箇所を確認しUI/UX向上に役立てることができます。

ユーザーのエラーの再現が今回の目的なので、エラー発生時のみSession Replayを記録するようにしました。

Set up

こちらを参考に、以下のような設定にしました。

import * as Sentry from "@sentry/vue";

Sentry.init({
  replaysSessionSampleRate: 0.0, // 正常時の記録は不要なので0.0

  replaysOnErrorSampleRate: 1.0, // エラーを記録したいので1.0

  integrations: [
    Sentry.replayIntegration({
      maskAllText: true, // テキストは個人情報を含むのでマスキング
      blockAllMedia: true, // img、svgやvideoなどは全て記録しない
      networkCaptureBodies: false // リクエスト・レスポンスボディは記録しない
    }),
  ],
});

細かい設定がいろいろできるので、詳細は以下を参照してください。
https://docs.sentry.io/platforms/javascript/session-replay/configuration/

privacyについて

Session Replayでは、ユーザーが入力したパスワードや個人情報を記録しないようにできます。

Masking、Blocking、Ignoringの3種類あります。

Masking

  • テキストをマスキングする
    • ユーザーが入力したテキストに限らず、画面に表示されているテキストも対象
  • defaultで*でマスキング

Blocking

  • 指定した要素ごとマスキングする
  • マスキングされると、空欄スペースになる

Ignoring

  • フォームのみ指定可能
  • 再生した時に、inputフィールド内に文字が出てこなくなる

class属性などを指定して、個別にマスキング対象を指定可能です

以下を参照ください。
https://docs.sentry.io/platforms/javascript/guides/vue/session-replay/privacy/#privacy-configuration

request・response body はデフォルトでは収集しません

収集するのは、URL、request・response body size、method、status codeです。
収集する項目をカスタマイズするには、networkDetailAllowUrlsnetworkCaptureBodies を設定します。
request・response bodyを収集する場合でも、クレジットカード情報、社会保障番号、パスワードなどSentryがパターンマッチで検知してScrubしてくれます。

送信前の録画に対して操作できるbeforeAddRecordingEvent関数

beforeAddRecordingEventを使用することで、画面録画から個人情報を削除したり特定の録画イベントを無視することができます。

現在の弊社の運用ルール

フロントエンドのアラート内容は玉石混合で、全てを解決するのは現実的ではありません。発生期間、priorityやステータスなどで適切にラベリングし、優先順位をつけて対応するようにしました。

ノイズになるため、エラーが発生してもリアルタイム通知はしていません。ただし重要度の高いエラーを見逃してしまう可能性があるため、短時間に大量のエラーが発生した場合は通知する予定です。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?