例外クラスへのコンテキスト追加が簡単に――honeybadger Ruby Gem 3.2の新機能
私たちは先日、honeybadger Ruby Gemのバージョン3.2をリリースしました。このリリースには、エラーレポートへのコンテキスト追加をこれまで以上に簡単に行える新機能が含まれています。
概要(tl;dr)
honeybadger gemでは、任意の例外クラスに #to_honeybadger_context メソッドを定義できるようになりました。その例外のインスタンスが発生してHoneybadgerに報告されると、コンテキストが自動的にエラーレポートに含まれます。
class MyError < StandardError
attr_reader :custom_attribute
def initialize(err, custom_attribute)
@custom_attribute = custom_attribute
super(err)
end
def to_honeybadger_context
{
custom_attribute: custom_attribute
}
end
end
raise MyError.new("Something went wrong", { foo: 'bar' })
# Honeybadgerのコンテキストには以下が含まれます:
# {
# custom_attribute: {
# foo: 'bar'
# }
# }
コンテキストとは?
コンテキストとは、アプリケーション内でエラーが発生した際に、追加のデータをHoneybadgerへ送信できる仕組みです。Railsでは、Ruby gemが提供する Honeybadger.context メソッドを使って、現在のリクエストに対するコンテキストを設定できます。
Honeybadger.context({
user_email: 'user@example.com'
})
現在のリクエスト(バックグラウンドワーカーを実行している場合はジョブ)内で発生するすべてのエラーには、それぞれ固有のコンテキストデータが付与されます。
コンテキストデータの中身は自由ですが、一般的にはログイン中ユーザーのユーザーIDやメールアドレス、デバッグに役立つ生のPOSTデータなどの関連ペイロード、バックグラウンドジョブのIDなどが含まれます。
また、エラーを手動で報告する際に、ローカルなコンテキストを追加することも可能です。
Honeybadger.notify(exception, context: {
user_email: 'user@example.com'
})
豆知識:コンテキストには何でも入れられますが、Honeybadgerにはいくつか「特別な」コンテキストキーが存在します。例えば、エラーレポートに user_email キーを含めると、Honeybadgerはエラーごとに影響を受けたユーザーのレポートを自動生成します。
例外からコンテキストを追加する
コンテキストの中には、リクエストではなく例外そのものに紐づくものもあります。例えば、faraday gemを使ってHTTPリクエストを行うケースを考えてみましょう。
require 'faraday'
conn = Faraday.new(:url => 'https://example.com') do |faraday|
faraday.response :raise_error # リクエストが成功しなかった場合はエラーを発生させる
faraday.adapter Faraday.default_adapter
end
response = conn.get('/does-not-exist') # => Faraday::ResourceNotFound
上記のコードは、次の例外を発生させます。
Faraday::ResourceNotFound: the server responded with status 404
Honeybadgerは(適切に設定されていれば)このエラーを自動的に報告しますが、response オブジェクトに関する情報は含まれません。特に500レスポンスのように原因が分かりにくいサーバーエラーの場合、この情報があるとデバッグが格段に楽になります。
GitHub上で Faraday::ResourceNotFound の定義を確認すると、これは実は ClientError の一種であり、ClientError は各インスタンスに response オブジェクトを保持する属性を定義していることが分かります。
この情報を活用すれば、Faraday::ClientError のインスタンスを rescue し、Honeybadger.notify を使ってレスポンスデータをコンテキストに追加できます。
begin
response = conn.get('/does-not-exist')
rescue Faraday::ClientError => err
Honeybadger.notify(err, context: {
response_status: err.response.status,
response_headers: err.response.headers
})
# 追加のエラーハンドリング...
end
これにより、失敗したリクエストをレスポンスに関する追加情報とともにHoneybadgerへ報告できます。
このパターンは、エラー発生時に例外固有のコンテキストを追加する手法として有効ですが、rescue文やカスタム通知ロジックがコードを散らかし、可読性の低下や余計なオーバーヘッドを招きます。実は、もっと良い方法があるのです。
新機能:例外レベルのコンテキスト
エラーを手動で報告する代わりに、コンテキストを例外クラス自体に定義できるようになりました。Honeybadgerは、エラーがどこで最終的に報告されたとしても、このコンテキストを自動的に検出して取り込みます。
先ほどの例に戻り、見苦しい rescue 文を書く代わりに、Honeybadgerの組み込みレポート機能に例外処理を任せてみましょう。
response = conn.get('/does-not-exist') # => Faraday::ResourceNotFound
その代わりに、例外が報告される際にHoneybadgerがチェックする特別なメソッドである #to_honeybadger_context を Faraday::ClientError に追加します。
Faraday::ClientError.class_eval do
def to_honeybadger_context
{
response_status: response.status,
response_headers: response.headers
}
end
end
Faraday::ClientError に #to_honeybadger_context メソッドを追加するだけで、コードを汚すことなく、該当するエラーが発生するたびにレスポンスのコンテキストを自動的に取得できるようになります!
-
Rubyでカスタム例外を作成する方法【初心者向けガイド】
Rubyでは、独自の例外クラスを簡単に作成できます。この記事では、カスタム例外を作るための基本的な手順を、コード例とともにわかりやすく解説します。 1. 新しいクラスを作成する Rubyにおいて、例外も他のオブジェクトと同じくクラスとして定義されています。新しい種類の例外を作りたい場合は、StandardError、あるいはそのサブクラスを継承したクラスを定義するだけでOKです。 class MyError < StandardError end raise MyError 慣例として、新しく作る例外クラスの名前は「Error」で終わるように命名します。また、カスタム例外をモジュ
-
なぜクラスを作るのか?抽象化の重要性と良いクラス設計の基本
前回の記事「なぜnilを使うのか」に続き、普段当たり前と思って使っているものについても、同じ問いを立ててみるのは良いアイデアではないでしょうか。 例えば… 巨大で醜いコードの塊を1つ作るのではなく、なぜ私たちはクラスを使うのでしょうか? 基本的なレベルで言えば、コードとデータを論理的な単位に整理するためにクラスを使います。しかし、それだけではありません。 クラスを使うと、抽象化(abstraction)を作り出せるのです。 抽象化とは何か? 実は、私たちは毎日、毎分、抽象化を利用しています。 今この記事を書いているキーボードは、次のようなもので構成されています。 ケーブル Cherry MX