STORES Product Blog

こだわりを持ったお商売を支える「STORES」のテクノロジー部門のメンバーによるブログです。

Sentry の fingerprint を活用してエラー整理をした話

*本記事は STORES Advent Calendar 2023 5日目の記事です

こんにちは。リテール開発本部に所属しています、tommy です。

STORES では、エラー監視ツールとして Sentry を導入して、日々開発をしています。

sentry.io

今回は、直近外部サービスのAPIを利用する開発をしていた際に、Sentryのエラー整理に fingerprint を活用した話について紹介いたします。

また、 STORES のプロダクトでのSentryの活用についてはこちらのブログにまとめてくれているので合わせてぜひご覧になってください。

product.st.inc

背景

私が所属するリテール開発本部でのプロダクト開発において、利用している外部サービスをあたらしいサービスに切り替える開発をしていました。

その外部サービスのAPIレスポンスは、エラーの場合、body にエラーコードとエラーメッセージを含む構造です。

{ "result": false, "errors": [ { "code": 1000, "message": "error message" } ] }

この開発では、既存APIと並行して、新規APIへリクエストを行い、正常に切り替えられるかどうかを確かめながら実装していました。

ここで、新規APIリクエストの結果がエラーだった際には、どのエンドポイントだったとしても共通のエラーハンドリングにより、Sentry にエラーとしてイベントを飛ばしていました。

しかしこの形だと「呼び出し箇所の種類 × 外部サービスへの実行APIの種類 × エラーの種類」 という組み合わせで、それぞれ違うissueとして大量に作成されてしまってしました。

エラーコードが同じでもissueが分割されてしまっている

Sentry と Slack を連携し、普段運用しているため、新規 issueのたびに通知がきてしまい、大事な通知を見落としてしまいかねないという影響もありました。

また、サービスの導入というところでどのようなエラーの種類が発生しうるのか、というところも合わせて把握したかったのですが、それもしづらい形になってしまっていました。

Sentryでは、エラーイベントを issue という単位で管理し、各 issue は fingerprint という独自の情報を持っています。 fingerprint は、デフォルトではスタックトレース、例外情報、エラーメッセージなどを基に生成されます。

docs.sentry.io

実際にSentryの各 issue ページの一番下に fingerprint の情報がのっています。

fingerprint を活用した issue のグルーピング

Sentryでは、前述した fingerprintを変更拡張することができ、用途にあわせてグルーピングさせることができます。

ドキュメント上では4種類の方法が紹介されています。

  • Merging Issues

    • 手動で特定の issue を選択し、マージしていく方法
  • Fingerprint Rules

    • 送られてくるイベントに対して、特定の条件と条件に当てはまる場合に設定したい fingerprint を 指定する方法
  • Stack Trace Rules

    • 送られてくるイベントに対して、fingerprint を構成する スタックトレースの内容を、条件をしていして変更する方法
  • SDK Fingerprinting

    • SDK経由でイベント送信時に fingerprint を指定する方法

実際の設定

今回は、外部サービスへのAPIレスポンスのステータスコードやエラーコードごとに issue をわけたかったので、 SDK Fingerprinting で対応しました。

sentry-ruby を導入しているので、RubySDKページに載っているコード例を参考にのせますが、 設定は簡単で、このように fingerprint という key を追加し、値に配列で fingerprint としていれたい情報を渡すだけです。

def do_something(action_name)
  # some code
rescue => exception
  Sentry.capture_exception(exception, fingerprint: [__method__, action_name])
end

docs.sentry.io

エラーの種類の単位でわけたかったので、エラーハンドリングの共通処理部分で以下のように fingerprint を設定してイベントを飛ばすように変更しました。

# 各エンドポイントへのリクエストでエラーが発生した際に共通で呼び出す
def handle_error(error, action, status_code, error_code)
  Sentry.capture_message(
    "API Request Error. status code: #{status_code}, error code: #{error_code}",
    # fingerprint の引数に指定したい値を配列で渡す
    fingerprint: Rails.env.production? ? ['api request error', action, error.class, error.status_code, error.error_code] : nil,
  )
end

通常では Sentry側の自動グルーピングで環境が別の場合、issueは分割されますが、fingerprint を設定してしまうと、別環境でも同一のissueと見なされてしまうため指定しています。

fingerprint を nil に指定した場合は、 デフォルトの fingerprint 設定が適用されて issue が作られます。

結果

これを設定したことにより、利用APIの種類ごと、エラーの種類ごと、に分類でき、Sentry上での issue を整理できました。

指定したfingerprintの単位で分かれている

issue で表示されている fingerprint は以下のようになっていて、custom-fingerprint として指定した形に上書きできていることが確認できます。

issue がまとまったことにより、issue単位で設定ができる特定条件まで通知をしないなどの Archive 設定を、分割したエラーの種類の単位で設定ができるようになり、Slackに通知がきすぎてしまう問題も解決できました。

また、詳細は省きますが、Sentry には tag という issue に対する補足情報がついています。

今回エラーの種類ごとにissueを設定しましたが、tag を活用することで、transaction や url と言った情報から呼び出し箇所の内訳もみることができます。

issueに含まれるイベントの中で、URLごとに発生件数や詳細をみることができる

まとめ

fingerprint を活用した、エラー整理の話でした。

途中取り上げた他のグルーピング手法もいろいろあるので、ぜひ調べて活用してみてください。

おわりに

本記事は STORES Advent Calendar 2023 5日目の記事でした!

次回は soh さんです。

soh さんは2日目にも Advent Calendar の記事を書いているので、合わせてぜひ読んでみてください!

パスキーは何を解決するのか - STORES Product Blog