Sentryを入れてRailsのエラー監視ををする(sentry-ruby, sentry-rails)

Sentryというエラー監視サービスがあります。少し前までsentry-ravenというGemで導入していましたが、sentry-ravenはメンテナンスモードに入り、変わりにsentry-ruby, sentry-railsを使うように案内されていました。

今回はそれをキャッチアップしながら導入してみます。

概要

  • エラー監視のためにsentryをRailsで使えるようにしたい
  • sentry-Ruby, sentry-railsを使ってsentryを導入する(not sentry-raven)
  • 実際に試してみる

Sentry is何?

Sentryとはアプリケーション監視、とりわけエラー監視ツールのSaaSです。Developer Planであれば件数の制限こそありますが無料で使いはじめることができます。

フロントエンドでもサーバーサイドでもどちらでも使うことができ、対応する言語やフレームワークも多く、導入も簡単なので手始めに入れるにはもってこいです。

なぜやったか

動機はエラー監視したいこと。やはり動作確認だけでは限界がありますし、ユーザーが実際にどんなエラーに遭遇しているかも知りたいです。また関連するAPIなどを使っている場合、連携先に問題がおこってる場合でも把握しやすいです。

冒頭でも書いたように、Railsで使うには今まではsentry-ravenというGemを使っていました。それが開発が終了し、メンテンスモードに入りました。これからはsentry-rubysentry-railsを使うように案内されているため、実際にやりながら導入してみようという流れです。

期待すること

sentry-ravenを使わない方法でRailsで出たエラーをsentryで監視、なんらかの方法で開発者に通知する、というのが今回のゴールです。

実際やったこと

Sentryに登録

ここからSignUpします(すでにしてある場合は不要)

次に使うRailsプロジェクト用にSentryのProjectを作ります。
(こちらもすでに設定されていれば不要)

導入

まず公式ドキュメントを見ます。

基本はこのドキュメントしたがってやります。
もしくはSentryのコンソールにSetup Sentryとステップにわかれた案内があるのでそちらがわかりやすいかもしれません。

Gemfileに

gem "sentry-ruby"
gem "sentry-rails"

を書いてbundle installですね。場合によってはproduction環境用のみのインストールでも良いかもしれません。そのへんは各環境と設定に応じて。

次にconfig/initializers/sentry.rbを作って

Sentry.init do |config|
  config.dsn = 'https://examplePublicKey@o0.ingest.sentry.io/0' # ここは書き換えが必要
  config.breadcrumbs_logger = [:active_support_logger]

  # To activate performance monitoring, set one of these options.
  # We recommend adjusting the value in production:
  config.traces_sample_rate = 0.5
  # or
  config.traces_sampler = lambda do |context|
    true
  end
end

を書きます(ドキュメントそのまま)。

最低限の設定はこれですが、config.dsnに入れるsentry_dsnはSentryのWebコンソールでcreate projectすると表示されています。一応ベタ書きではなく環境変数などで指定するのを推奨されているのでご注意ください。

では、ローカルの開発環境で試して適当にエラーを起こしてみます。
そしてSentryのWebコンソールをみると、こんな感じで記録されていますね。

これでひとまずは成功です。

設定

config.enabled_environments = %w[production]
config.environment = Rails.env

基本的に開発環境では必要ないので対象をproductionに絞ります。例えば動作検証要にstaging環境とかあればそれも含めるほうが多いことでしょう。

その他、大事なのはエラーを出したときに個人情報などの秘匿すべきデータの扱いです。

config.send_default_pii = true

これは場合によりけりです。デフォルトがfalseになっていて、trueにすると、UserのIP、Cookie、request bodyがSentryに送信されるようになります。
当然あるユーザを特定できる要素なため、扱いには注意が必要ですね。

例えば仮にどのユーザであるとか、同一のエラーは同一のユーザかどうかを見たい程度であれば、ApplicationControllerなどで

class ApplicationController < ActionController::Base
  before_action :set_sentry_context

  private

  def set_sentry_context
    Sentry.set_user(id: current_user&.id)
  end
end

のようにしておけば、アプリケーション内の特定の情報をSentryに渡すことができます。

その他の注意点としては秘匿すべき情報を渡さないようにする処理、いわゆるサニタイズです。Sentryが外部サービスである以上、それが送信されること自体を避けなければなりません。これは従来のsentry-ravenで提供されていた仕組み(config.sanitize_fields)が使えなくなっていて、今はこのように書きます。

Sentry.init do |config|
  filter = ActiveSupport::ParameterFilter.new(Rails.application.config.filter_parameters)
  config.before_send = lambda do |event, hint|
    # note1: if you have config.async configured, the event here will be a Hash instead of an Event object
    # note2: the code below is just an example, you should adjust the logic based on your needs
    event.request.data = filter.filter(event.request.data)
    event
  end
end

(こうなった経緯はAdd better documentation for sanitizing data · Issue #1140 · getsentry/sentry-ruby)にIssueがあります)。
もちろん、デフォルトでフィルタされる以外のものでフィルタしたいものがあれば、Rails側のRails.application.config.filter_parametersに追加しておいてください。

その他の詳しい設定は一度こちらに目を通すといいでしょう。以前にsentry-ravenを使っていた場合なども設定のAPIが変更されているため注意が必要です。

通知する

Sentryでエラーを検知したらそれを何らかの方法で通知が来ると便利です。
Slack Integrationが便利なんですがBusiness Plan以上でないと使えないため別の方法を考えます。
(以前Slackで使われていた連携も使えないことはないのですが、Legacy Integrationと定義されておりいつ使えなくなるかわからないためここでは割愛します)。

Business Plan以上を使ってるのであれば何も気にせず以下のドキュメントを参考にすればすぐできるはずです。

ひとまずオーソドックスにE-mailで通知するようにしてみましょう。

SentryのWebコンソールからサイドメニューのAlertsを選択、続いてCreate Alert Ruleを押して新しいルールを作ります。

ルールはひとまず最低限必要なのはタイトルとどうするか、です。
適当なタイトルをつけ、THENをsend e-mailにして宛先を選びます。

これでもう一度適当なエラーを起こしてみてSentryからメールが届いたらOKですね。

今回触れなかったこと

すでに今までsentry-ravenを使っていた場合はこちらに移行ガイドがあります。

また、sentry-sidekiqを使うことでSidekiq経由で非同期的にエラー監視ができます。できればこれもやっておいたほうが良いでしょう。

非同期ではなく同期的だと万が一Sentryサービスのサーバー側が応答しない場合、処理がそこで止まってしまいます。ユーザーへの応答が無駄に遅くなりますし、タイムアウトした場合ユーザーに通知されるエラー内容も変わってしまいます。 ただし、Sidekiqが動いていることが前提になるため今回は導入としては割愛します。

感想

今回はSentryをライブラリを新しいものでRailsに入れてみました。しかし、僕はたまたまTwitterで見かけたので今回のアップデートに気づいたんですが、以前から使っててそのまま動いてるとライブラリが変わるとなかなか気づけないですね。

Sentryはサーバーサイドだけでなく、フロントエンドでも比較的簡単に導入できるので、ひとまず最初の環境構築のフェーズでシュっと入れておくのを癖づけるが良いだろうなあと思いました。

BrakemanでRailsの脆弱性を検知して防ぐJavaScriptで正確に文字数をカウントする