Skip to content

Commit e0ec934

Browse files
committed
working prototype
1 parent 269bd61 commit e0ec934

File tree

16 files changed

+150
-7
lines changed

16 files changed

+150
-7
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
/test/dummy/log/*.log
99
/test/dummy/storage/
1010
/test/dummy/tmp/
11+
Gemfile.lock

Gemfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ gem "puma"
99
gem "sqlite3"
1010

1111
# Start debugger with binding.b [https://github.com/ruby/debug]
12-
# gem "debug", ">= 1.0.0"
12+
gem "debug", ">= 1.0.0"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<li><%= frame %></li>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>No backtrace available</p>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<h1><%= @error.class %></h1>
2+
<p><%= @error.message %></p>
3+
4+
<div>
5+
<%= render(partial: "frame", collection: @backtrace) || render("no_backtrace") -%>
6+
</div>

lib/email_error_reporter.rb

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
require "email_error_reporter/version"
2-
require "email_error_reporter/railtie"
2+
require "email_error_reporter/engine"
33

44
module EmailErrorReporter
5-
# Your code goes here...
5+
extend ActiveSupport::Autoload
6+
7+
autoload :ErrorMailer
8+
autoload :Subscriber
9+
autoload :ExceptionSerializer
610
end

lib/email_error_reporter/engine.rb

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module EmailErrorReporter
2+
class Engine < ::Rails::Engine
3+
isolate_namespace EmailErrorReporter
4+
5+
config.email_error_reporter = ActiveSupport::OrderedOptions.new
6+
config.email_error_reporter.to = []
7+
8+
initializer "email_error_reporter.error_subscribe" do
9+
Rails.error.subscribe(Subscriber.new)
10+
end
11+
12+
# ActiveJob cannot (de)-serialize exceptions by default
13+
initializer "email_error_reporter.exception_serializer" do |app|
14+
app.config.active_job.custom_serializers << ExceptionSerializer
15+
end
16+
end
17+
end
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module EmailErrorReporter
2+
class ErrorMailer < ActionMailer::Base
3+
def error(error, handled:, severity:, context:, source: nil)
4+
@error = error
5+
@handled = handled
6+
@severity = severity
7+
@context = context
8+
@source = source
9+
10+
@backtrace = Array.wrap(error.backtrace)
11+
12+
mail(
13+
subject: "#{error.class}",
14+
to: Rails.application.config.email_error_reporter.to
15+
)
16+
end
17+
end
18+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module EmailErrorReporter
2+
class ExceptionSerializer < ActiveJob::Serializers::ObjectSerializer
3+
def serialize(exception)
4+
super(
5+
exception_class: exception.class.to_s,
6+
message: exception.message,
7+
backtrace: exception.backtrace
8+
)
9+
end
10+
11+
def deserialize(hash)
12+
hash[:exception_class].constantize.new(hash[:message]).tap do |e|
13+
e.set_backtrace(hash[:backtrace])
14+
end
15+
end
16+
17+
private
18+
19+
def klass
20+
Exception
21+
end
22+
end
23+
end

lib/email_error_reporter/railtie.rb

-4
This file was deleted.
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module EmailErrorReporter
2+
class Subscriber
3+
def report(error, handled:, severity:, context:, source: nil)
4+
ErrorMailer.error(error, handled: handled, context: context, source: source).deliver_later
5+
end
6+
end
7+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<h1>Exception</h1>
2+
<p>some message</p>
3+
4+
<div>
5+
<p>No backtrace available</p>
6+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<h1>Exception</h1>
2+
<p>some message</p>
3+
4+
<div>
5+
<li>foo</li>
6+
<li>bar</li>
7+
</div>

test/error_mailer_test.rb

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
require "test_helper"
2+
3+
class EmailErrorReporter::ErrorMailerTest < ActionMailer::TestCase
4+
test "renders the template correctly" do
5+
exception = Exception.new("some message")
6+
email = EmailErrorReporter::ErrorMailer.error(
7+
exception,
8+
handled: true,
9+
severity: :info,
10+
context: {}
11+
)
12+
assert_equal [], email.to
13+
assert_equal "Exception", email.subject
14+
assert_equal read_fixture("error").join, email.body.to_s
15+
end
16+
17+
test "renders a backtrace" do
18+
exception = Exception.new("some message")
19+
exception.set_backtrace(["foo", "bar"])
20+
email = EmailErrorReporter::ErrorMailer.error(
21+
exception,
22+
handled: true,
23+
severity: :info,
24+
context: {}
25+
)
26+
assert_equal [], email.to
27+
assert_equal "Exception", email.subject
28+
assert_equal read_fixture("error_with_backtrace").join, email.body.to_s
29+
end
30+
end

test/subscriber_test.rb

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
require "test_helper"
2+
3+
class SubscriberTest < ActiveSupport::TestCase
4+
include ActionMailer::TestHelper
5+
6+
TestError = Class.new(StandardError)
7+
8+
test "enqueues a mail with the reported error" do
9+
Rails.error.record(TestError) do
10+
raise TestError
11+
end
12+
13+
rescue TestError => e
14+
assert_enqueued_email_with EmailErrorReporter::ErrorMailer, :error, args: ->(args) {
15+
# TODO: find out, why args.first == e is false
16+
[
17+
args.first.message == e.message,
18+
args.first.backtrace == e.backtrace,
19+
args.first.class == e.class
20+
].all?
21+
}
22+
end
23+
end

test/test_helper.rb

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
ActiveRecord::Migrator.migrations_paths = [File.expand_path("../test/dummy/db/migrate", __dir__)]
66
require "rails/test_help"
77

8+
# require debugger for tests
9+
require "debug"
10+
811
# Load fixtures from the engine
912
if ActiveSupport::TestCase.respond_to?(:fixture_paths=)
1013
ActiveSupport::TestCase.fixture_paths = [File.expand_path("fixtures", __dir__)]

0 commit comments

Comments
 (0)