edge
詳細はrubyonrails.orgで: もっとRuby on Rails

Railsアプリケーションにおけるエラーレポート

このガイドでは、Ruby on Railsアプリケーションで発生する例外を管理する方法について紹介します。

このガイドを読み終えると、以下のことがわかるようになります:

1 エラーレポート

Railsのエラーレポーターは、アプリケーションで発生する例外を収集し、指定したサービスや場所にレポートするための標準的な方法を提供します。

エラーレポーターは、次のようなボイラープレートのエラーハンドリングコードを置き換えることを目指しています:

begin
  do_something
rescue SomethingIsBroken => error
  MyErrorReportingService.notify(error)
end

一貫したインターフェースで次のように書くことができます:

Rails.error.handle(SomethingIsBroken) do
  do_something
end

Railsは、HTTPリクエスト、ジョブ、rails runnerの実行などのすべての実行をエラーレポーターでラップするため、アプリ内で処理されないエラーは自動的にエラーレポートサービスにサブスクライバを介してレポートされます。

これにより、サードパーティのエラーレポートライブラリは、未処理の例外をキャプチャするためにRackミドルウェアを挿入したり、モンキーパッチを適用する必要がなくなります。ActiveSupportを使用するライブラリは、以前はログで失われていた警告を非侵入的にレポートするためにこれを使用することもできます。

Railsのエラーレポーターの使用は必須ではありません。他のエラーのキャプチャ手段は引き続き機能します。

1.1 レポータにサブスクライブする

エラーレポーターを使用するには、サブスクライバが必要です。サブスクライバは、reportメソッドを持つ任意のオブジェクトです。アプリケーションでエラーが発生するか、手動でレポートされると、Railsのエラーレポーターはこのメソッドをエラーオブジェクトといくつかのオプションとともに呼び出します。

SentryのHoneybadgerのような一部のエラーレポートライブラリは、自動的にサブスクライバを登録します。詳細については、プロバイダのドキュメントを参照してください。

カスタムサブスクライバも作成できます。例:

# config/initializers/error_subscriber.rb
class ErrorSubscriber
  def report(error, handled:, severity:, context:, source: nil)
    MyErrorReportingService.report_error(error, context: context, handled: handled, level: severity)
  end
end

サブスクライバクラスを定義した後、Rails.error.subscribeメソッドを呼び出して登録します:

Rails.error.subscribe(ErrorSubscriber.new)

登録するサブスクライバは何個でも構いません。Railsは登録された順序で順番に呼び出します。

注意:Railsのエラーレポーターは、環境に関係なく登録されたサブスクライバを常に呼び出します。ただし、多くのエラーレポートサービスはデフォルトで本番環境でのみエラーをレポートします。必要に応じて環境を設定してテストする必要があります。

1.2 エラーレポータの使用

エラーレポータには3つの使用方法があります:

1.2.1 エラーのレポートとエラーのスワロー

Rails.error.handleは、ブロック内で発生したエラーをレポートします。その後、エラーはスワローされ、ブロックの外側のコードは通常通り実行されます。

result = Rails.error.handle do
  1 + '1' # TypeErrorを発生させる
end
result # => nil
1 + 1 # これは実行されます

ブロック内でエラーが発生しない場合、Rails.error.handleはブロックの結果を返します。エラーが発生した場合はnilを返します。fallbackを指定することでこれをオーバーライドすることもできます:

user = Rails.error.handle(fallback: -> { User.anonymous }) do
  User.find_by(params[:id])
end

1.2.2 エラーのレポートとエラーの再発生

Rails.error.recordは、すべての登録されたサブスクライバにエラーをレポートし、その後エラーを再発生させます。つまり、コードの残りの部分は実行されません。

Rails.error.record do
  1 + '1' # TypeErrorを発生させる
end
1 + 1 # これは実行されません

ブロック内でエラーが発生しない場合、Rails.error.recordはブロックの結果を返します。

1.2.3 手動でエラーをレポートする

Rails.error.reportを呼び出すことで、手動でエラーをレポートすることもできます:

begin
  # コード
rescue StandardError => e
  Rails.error.report(e)
end

渡すオプションは、エラーサブスクライバに渡されます。

1.3 エラーレポートオプション

すべての3つのレポートAPI(#handle#record#report)は、以下のオプションをサポートしており、登録されたすべてのサブスクライバに渡されます:

  • handled:エラーが処理されたかどうかを示すBoolean。デフォルトではtrueに設定されています。#recordではこれがfalseに設定されます。
  • severity:エラーの重要度を示すSymbol。期待される値は、:error:warning:infoです。#handleではこれが:warningに設定され、#recordでは:errorに設定されます。
  • context:エラーに関する詳細なコンテキスト(リクエストやユーザーの詳細など)を提供するためのHash
  • source:エラーのソースに関するString。デフォルトのソースは「application」です。内部ライブラリによって報告されるエラーは他のソースを設定する場合があります。たとえば、Redisキャッシュライブラリは「redis_cache_store.active_support」を使用するかもしれません。サブスクライバはソースを使用して、興味のないエラーを無視することができます。 ruby Rails.error.handle(context: { user_id: user.id }, severity: :info) do # ... end

1.4 エラークラスでのフィルタリング

Rails.error.handleRails.error.recordを使用して、特定のクラスのエラーのみを報告するように選択することもできます。例えば:

Rails.error.handle(IOError) do
  1 + '1' # TypeErrorが発生する
end
1 + 1 # TypeErrorはIOErrorではないため、実行されません

ここでは、TypeErrorはRailsのエラーレポーターにキャプチャされません。IOErrorとその子孫のインスタンスのみが報告されます。他のエラーは通常通りに発生します。

1.5 グローバルなコンテキストの設定

contextオプションを介してコンテキストを設定するだけでなく、#set_context APIを使用することもできます。例えば:

Rails.error.set_context(section: "checkout", user_id: @user.id)

この方法で設定されたコンテキストは、contextオプションとマージされます。

Rails.error.set_context(a: 1)
Rails.error.handle(context: { b: 2 }) { raise }
# 報告されるコンテキストは: {:a=>1, :b=>2}
Rails.error.handle(context: { b: 3 }) { raise }
# 報告されるコンテキストは: {:a=>1, :b=>3}

1.6 ライブラリ向け

エラーレポートライブラリは、Railtie内でサブスクライバーを登録することができます。

module MySdk
  class Railtie < ::Rails::Railtie
    initializer "my_sdk.error_subscribe" do
      Rails.error.subscribe(MyErrorSubscriber.new)
    end
  end
end

エラーサブスクライバーを登録した場合、Rackミドルウェアなどの他のエラーメカニズムがある場合、エラーが複数回報告される可能性があります。他のメカニズムを削除するか、レポート機能を調整して、以前に見た例外の報告をスキップするようにする必要があります。

フィードバック

このガイドの品質向上にご協力ください。

タイポや事実の誤りを見つけた場合は、ぜひ貢献してください。 開始するには、ドキュメントへの貢献セクションを読んでください。

不完全なコンテンツや最新でない情報も見つかるかもしれません。 メインのドキュメントに不足しているドキュメントを追加してください。 修正済みかどうかは、まずEdge Guidesを確認してください。 スタイルと規約については、Ruby on Rails Guides Guidelinesを確認してください。

修正すべき点を見つけたが、自分で修正できない場合は、 問題を報告してください

そして最後に、Ruby on Railsのドキュメントに関するあらゆる議論は、公式のRuby on Railsフォーラムで大歓迎です。