Sentry運用日記 - 検知されるエラーをbeforeSendでフィルタリングする

どうも、フロントエンドエンジニアの田口です。
以前Sentryについての記事を書いたのですが、導入してから運用として問題が出てきたので、その対処をしたという続編みたいなものになります。
Sentryについては「導入した!」という記事は多いのですが、その後の運用についてはあまり語られていないような気がしますので、導入したばかりや導入を検討中という方の参考になればという期待を込めて書かせていただきました。

前回↓
tech.trustbank.co.jp

前回のあらすじ

クライアントサイドでのエラー検知のためにSentryを導入した

Issue多すぎ問題

Sentryの導入時、エラーがどれほどの量検知されるのか、また導入によるデメリットなどは無いかの確認のため、いきなりサービスの全ページを監視するのではなく、監視範囲を徐々に広げていくような導入方法を採りました。最初はユーザーの訪問数も少なめなページで様子を見て、その後は訪問数の多いページを少しずつ監視対象として追加していき、最終的に全ページを監視対象としました。
しかし、訪問数の多いページを追加監視していくのに比例して、明らかにエラー検知数が増加しており、3月期にはTeam Planについてくるエラー検知クォータ(5万イベント)を25日目にはオーバーし、クォータを追加することになりました。
導入によるデメリットもなく、エラー検知のメリットを感じ始めていたことを踏まえ、監視対象の拡大は進める一方で、多すぎるIssueによりトリアージの判断も困難になってしまっていたため、増えすぎた検知数をなんとかする必要性も高まりました。

対処しなくて良いエラー、対処すべきエラーの見極め

そもそもどんなエラーが増えているのかを確認するため、加速度的に増えていくIssuesの件数にツラさを覚えつつも、検知数の多いIssueから分析を開始しました。
これは普通のエラーですね。エラーの原因も分析が可能ですし、解消も容易です。

画像はイメージです

一方でこのようなエラーも。

これは……?

最初のエラーと比較してみるとstack traceが何も出ていません。このIssueの内容から原因を調査して対処するのはかなり厳しいものがあります。 *1
ツラいことに、こうしたIssueの数は分析可能なものと比較しても同じかそれ以上の量上がってきていました。エラーのトリアージ(優先度付け)として、このような分析困難なエラーに向き合うことは時間やSentryのクォータを丸々含めた「予算」の無駄になりますので、フィルタリングすることにしました。

フィルタリング方法の検討と実装

フィルタリング方法で最も簡単なのは管理画面で捨てたいものをポチポチとやればすぐに捨てられる方法ですが、果たしてSentryにあるのか…と思ったら、ありました。

削除しつつ将来にわたり無視する…完璧だ

しかしこの無視する機能、Teamプランでは使用できません。一つ上のBusinessプランが必要です。残念ですがこちらの使用は断念。
ということで管理画面からのフィルタリングはTeamプランではほとんど出来ないので、SDKによるフィルタリングを実装しました。

beforeSendという強力な味方

Sentry SDKには便利なオプションがいくつもあり*2、既にwhiteListUrls(allowUrls)によるURLでのフィルタリングやenvironmentによるIssueのタグ付けを導入していました。
今回のフィルタリングでは、beforeSendを使用しました。beforeSendは関数を登録でき、eventオブジェクトを返せばエラーをSentryに送り、nullを返せばエラーはSentryに送られずに破棄されます。
例えばstack traceの有無のみでフィルタリングするのであれば以下のような簡単な実装で済ませられます。

beforeSend(event) {
  try {
    const hasStacktrace = event.exception.values.some(value => {
      return value.stacktrace?.frames?.length > 0;
    });
    if (hasStacktrace) {
      return event;
    }
    return null;
  } catch {
    return event;
  }
}

beforeSendはかなり柔軟な実装ができますので、エラーに関する情報が詰まっている引数のeventの中身を一度確認してみることをおすすめします。
また上のスニペット例では引数としてeventしか使用していませんが、第二引数としてhintが使用可能です。
hintオブジェクトにはoriginalExceptionというプロパティがあり、Sentry特有のエラーのオブジェクトに変換される前のエラーが取得できます。が、内容的にはeventオブジェクトでも取得可能なもののようなので、今のところhintは使用していません。

Sentryの公式ドキュメントでもbeforeSendをはじめとするフィルタリングのアイデアがいくつか書かれていますので、こちらを見ながらサービスに必要なフィルタリングを実装していくのがGoodかと思います。

docs.sentry.io

Sentryの運用はフィルタリングが肝

beforeSendによるフィルタリングによって、上がってくるIssueのほとんどは分析可能なものになりました。数は多いのですが、これらは一つ一つバグとして潰していくことが可能です。
Sentryの運用をされている方の記事等を見ているとフィルタリングの重要性について書かれていることが多いので、重要性を認識してはいたのですが、今回の改善によってより一層認識を強くしました。
今後はSentryでバグを潰していくとともに、Sentry自体の運用についても定期的に見直していこうと思います。またアップデートをしたときにはここで記事を書きます。

それでは今回はこの辺で〜ノシ

ということでいつもの

トラストバンクではバグを分析し、それを修正することが得意なエンジニアを随時募集しております! www.wantedly.com

*1:ちなみにこのエラーについて調べたところ、マーケティング関連のタグ(GTMか何かで導入されている)でfetchで取得したいリソースがCORSエラーになっていたようです。allowUrlsでファイルのパスでフィルタリングしているのにIssueとして上がってしまう理由は分かっていません😓

*2:https://docs.sentry.io/platforms/javascript/configuration/options/