Skip to content

Commit 8110063

Browse files
authored
add sentry error reporter (#374)
1 parent 1a366ca commit 8110063

6 files changed

Lines changed: 139 additions & 14 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# frozen_string_literal: true
2+
3+
module Pliny
4+
module ErrorReporters
5+
class Sentry
6+
def notify(exception, context:, rack_env:)
7+
::Sentry.with_scope do |scope|
8+
configure_scope(scope, context: context, rack_env: rack_env)
9+
::Sentry.capture_exception(exception)
10+
end
11+
rescue Exception => e # rubocop:disable Lint/RescueException
12+
::Sentry.capture_exception(e)
13+
raise
14+
end
15+
16+
private
17+
18+
def configure_scope(scope, context:, rack_env:)
19+
scope.set_context("custom", context)
20+
21+
begin
22+
person_data = extract_person_data_from_controller(rack_env)
23+
if person_data && !person_data.empty?
24+
scope.set_user(
25+
id: person_data[:id],
26+
email: person_data[:email],
27+
username: person_data[:username],
28+
)
29+
end
30+
rescue => e
31+
::Sentry.capture_exception(e)
32+
end
33+
end
34+
35+
def extract_person_data_from_controller(env)
36+
env["sentry.person_data"] || {}
37+
end
38+
end
39+
end
40+
end

lib/template/Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ gem "rack-ssl"
1111
gem "rack-timeout", "~> 0.6"
1212
gem "rake"
1313
gem "rollbar"
14+
gem "sentry-ruby"
1415
gem "sequel", "~> 5.73"
1516
gem "sequel-paranoid"
1617
gem "sequel_pg", "~> 1.17", require: "sequel"

lib/template/config/initializers/rollbar.rb

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# frozen_string_literal: true
2+
3+
require "pliny/error_reporters/sentry"
4+
5+
Pliny::ErrorReporters.error_reporters << Pliny::ErrorReporters::Sentry
6+
7+
Sentry.init do |config|
8+
config.dsn = ENV["SENTRY_DSN"]
9+
config.environment = ENV["SENTRY_ENV"] || ENV["RACK_ENV"]
10+
config.enabled_environments = ENV["SENTRY_ENABLED_ENVIRONMENTS"]&.split(",") || %w[production staging]
11+
config.traces_sample_rate = ENV["SENTRY_TRACES_SAMPLE_RATE"]&.to_f || 0.1
12+
end
13+
14+
Pliny.use Sentry::Rack::CaptureExceptions

pliny.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Gem::Specification.new do |gem|
3434
gem.add_development_dependency "rake"
3535
gem.add_development_dependency "rollbar"
3636
gem.add_development_dependency "rspec"
37+
gem.add_development_dependency "sentry-ruby"
3738
gem.add_development_dependency "rubocop"
3839
gem.add_development_dependency "sequel"
3940
gem.add_development_dependency "sinatra-contrib"
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# frozen_string_literal: true
2+
3+
require "spec_helper"
4+
require "sentry-ruby"
5+
require "pliny/error_reporters/sentry"
6+
7+
describe Pliny::ErrorReporters::Sentry do
8+
subject(:reporter) { described_class.new }
9+
10+
describe "#notify" do
11+
let(:exception) { StandardError.new("Something went wrong") }
12+
let(:context) { { step: :foo } }
13+
let(:rack_env) { { "rack.input" => StringIO.new } }
14+
15+
subject(:notify) do
16+
reporter.notify(exception, context: context, rack_env: rack_env)
17+
end
18+
19+
before do
20+
allow(::Sentry).to receive(:with_scope).and_yield(scope)
21+
allow(::Sentry).to receive(:capture_exception)
22+
end
23+
24+
let(:scope) { instance_double("Sentry::Scope") }
25+
26+
before do
27+
allow(scope).to receive(:set_context)
28+
allow(scope).to receive(:set_user)
29+
end
30+
31+
it "creates a sentry scope" do
32+
notify
33+
expect(::Sentry).to have_received(:with_scope).once
34+
end
35+
36+
it "sets custom context" do
37+
notify
38+
expect(scope).to have_received(:set_context).with("custom", { step: :foo })
39+
end
40+
41+
it "captures the exception" do
42+
notify
43+
expect(::Sentry).to have_received(:capture_exception).with(exception)
44+
end
45+
46+
context "given a rack_env with sentry.person_data" do
47+
let(:rack_env) { { "sentry.person_data" => { id: 123, email: "test@example.com", username: "testuser" }, "rack.input" => StringIO.new } }
48+
49+
it "sets user context from sentry.person_data" do
50+
notify
51+
expect(scope).to have_received(:set_user).with(id: 123, email: "test@example.com", username: "testuser")
52+
end
53+
end
54+
55+
context "given a rack_env with empty sentry.person_data" do
56+
let(:rack_env) { { "sentry.person_data" => {}, "rack.input" => StringIO.new } }
57+
58+
it "does not set user context" do
59+
notify
60+
expect(scope).not_to have_received(:set_user)
61+
end
62+
end
63+
64+
context "given an empty rack_env" do
65+
let(:rack_env) { {} }
66+
67+
it "expects rack_env to be a hash" do
68+
assert_kind_of(Hash, rack_env)
69+
end
70+
71+
it "sets only custom context" do
72+
notify
73+
expect(scope).to have_received(:set_context).once.with("custom", { step: :foo })
74+
expect(scope).not_to have_received(:set_user)
75+
end
76+
77+
it "captures the exception" do
78+
notify
79+
expect(::Sentry).to have_received(:capture_exception).with(exception)
80+
end
81+
end
82+
end
83+
end

0 commit comments

Comments
 (0)