From 60ba3b97e70fe04c1b12b884d7cdcb70f6443222 Mon Sep 17 00:00:00 2001 From: Daniel Bright Date: Fri, 12 Sep 2025 10:18:09 -0700 Subject: [PATCH 1/5] add sentry error reporter --- lib/pliny/error_reporters/sentry.rb | 46 ++++++++++++ lib/template/Gemfile | 1 + lib/template/config/initializers/sentry.rb | 14 ++++ pliny.gemspec | 1 + spec/error_reporters/sentry_spec.rb | 85 ++++++++++++++++++++++ 5 files changed, 147 insertions(+) create mode 100644 lib/pliny/error_reporters/sentry.rb create mode 100644 lib/template/config/initializers/sentry.rb create mode 100644 spec/error_reporters/sentry_spec.rb diff --git a/lib/pliny/error_reporters/sentry.rb b/lib/pliny/error_reporters/sentry.rb new file mode 100644 index 00000000..f8fad8b0 --- /dev/null +++ b/lib/pliny/error_reporters/sentry.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require "sentry-ruby" + +module Pliny + module ErrorReporters + class Sentry + def notify(exception, context:, rack_env:) + ::Sentry.with_scope do |scope| + configure_scope(scope, context: context, rack_env: rack_env) + ::Sentry.capture_exception(exception) + end + rescue Exception => e # rubocop:disable Lint/RescueException + ::Sentry.capture_exception(e) + raise + end + + private + + def configure_scope(scope, context:, rack_env:) + scope.set_context("custom", context) + + begin + person_data = extract_person_data_from_controller(rack_env) + if person_data && !person_data.empty? + scope.set_user( + id: person_data[:id], + email: person_data[:email], + username: person_data[:username], + ) + end + rescue => e + ::Sentry.capture_exception(e) + end + end + + def extract_person_data_from_controller(env) + if env.key?("sentry.person_data") + env["sentry.person_data"] || {} + else + {} + end + end + end + end +end diff --git a/lib/template/Gemfile b/lib/template/Gemfile index bf0dc99b..8ea247c9 100644 --- a/lib/template/Gemfile +++ b/lib/template/Gemfile @@ -11,6 +11,7 @@ gem "rack-ssl" gem "rack-timeout", "~> 0.6" gem "rake" gem "rollbar" +gem "sentry-ruby" gem "sequel", "~> 5.73" gem "sequel-paranoid" gem "sequel_pg", "~> 1.17", require: "sequel" diff --git a/lib/template/config/initializers/sentry.rb b/lib/template/config/initializers/sentry.rb new file mode 100644 index 00000000..e36abdd1 --- /dev/null +++ b/lib/template/config/initializers/sentry.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require "pliny/error_reporters/sentry" + +Pliny::ErrorReporters.error_reporters << Pliny::ErrorReporters::Sentry + +Sentry.init do |config| + config.dsn = ENV["SENTRY_DSN"] + config.environment = ENV["SENTRY_ENV"] || ENV["RACK_ENV"] + config.enabled_environments = %w[production staging] + config.traces_sample_rate = 0.1 +end + +Pliny.use Sentry::Rack::CaptureExceptions diff --git a/pliny.gemspec b/pliny.gemspec index 662618c5..2db8a2f7 100644 --- a/pliny.gemspec +++ b/pliny.gemspec @@ -34,6 +34,7 @@ Gem::Specification.new do |gem| gem.add_development_dependency "rake" gem.add_development_dependency "rollbar" gem.add_development_dependency "rspec" + gem.add_development_dependency "sentry-ruby" gem.add_development_dependency "rubocop" gem.add_development_dependency "sequel" gem.add_development_dependency "sinatra-contrib" diff --git a/spec/error_reporters/sentry_spec.rb b/spec/error_reporters/sentry_spec.rb new file mode 100644 index 00000000..7feca8ab --- /dev/null +++ b/spec/error_reporters/sentry_spec.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +require "spec_helper" +require "sentry-ruby" +require "pliny/error_reporters/sentry" + +describe Pliny::ErrorReporters::Sentry do + subject(:reporter) { described_class.new } + + describe "#notify" do + let(:exception) { StandardError.new("Something went wrong") } + let(:context) { { step: :foo } } + let(:rack_env) { { "rack.input" => StringIO.new } } + + subject(:notify) do + reporter.notify(exception, context: context, rack_env: rack_env) + end + + before do + allow(::Sentry).to receive(:with_scope).and_yield(scope) + allow(::Sentry).to receive(:capture_exception) + end + + let(:scope) { instance_double("Sentry::Scope") } + + before do + allow(scope).to receive(:set_context) + allow(scope).to receive(:set_user) + end + + it "creates a sentry scope" do + notify + expect(::Sentry).to have_received(:with_scope).once + end + + it "sets custom context" do + notify + expect(scope).to have_received(:set_context).with("custom", { step: :foo }) + end + + it "captures the exception" do + notify + expect(::Sentry).to have_received(:capture_exception).with(exception) + end + + + context "given a rack_env with sentry.person_data" do + let(:rack_env) { { "sentry.person_data" => { id: 123, email: "test@example.com", username: "testuser" }, "rack.input" => StringIO.new } } + + it "sets user context from sentry.person_data" do + notify + expect(scope).to have_received(:set_user).with(id: 123, email: "test@example.com", username: "testuser") + end + end + + context "given a rack_env with empty sentry.person_data" do + let(:rack_env) { { "sentry.person_data" => {}, "rack.input" => StringIO.new } } + + it "does not set user context" do + notify + expect(scope).not_to have_received(:set_user) + end + end + + context "given an empty rack_env" do + let(:rack_env) { {} } + + it "expects rack_env to be a hash" do + assert_kind_of(Hash, rack_env) + end + + it "sets only custom context" do + notify + expect(scope).to have_received(:set_context).once.with("custom", { step: :foo }) + expect(scope).not_to have_received(:set_user) + end + + it "captures the exception" do + notify + expect(::Sentry).to have_received(:capture_exception).with(exception) + end + end + + end +end \ No newline at end of file From cc04fb2dd501bdcaf89af3557b641cc290c585b2 Mon Sep 17 00:00:00 2001 From: Daniel Bright Date: Tue, 16 Sep 2025 16:37:31 -0700 Subject: [PATCH 2/5] added defaults for ENV var --- lib/template/config/initializers/sentry.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/template/config/initializers/sentry.rb b/lib/template/config/initializers/sentry.rb index e36abdd1..c98ee496 100644 --- a/lib/template/config/initializers/sentry.rb +++ b/lib/template/config/initializers/sentry.rb @@ -7,8 +7,8 @@ Sentry.init do |config| config.dsn = ENV["SENTRY_DSN"] config.environment = ENV["SENTRY_ENV"] || ENV["RACK_ENV"] - config.enabled_environments = %w[production staging] - config.traces_sample_rate = 0.1 + config.enabled_environments = ENV["SENTRY_ENABLED_ENVIRONMENTS"]&.split(",") || %w[production staging] + config.traces_sample_rate = ENV["SENTRY_TRACES_SAMPLE_RATE"]&.to_f || 0.1 end Pliny.use Sentry::Rack::CaptureExceptions From be44b713882997ea8d6d9882a1ddbe6bb685a542 Mon Sep 17 00:00:00 2001 From: Dan <152929550+brahyt-sf@users.noreply.github.com> Date: Thu, 18 Sep 2025 08:48:12 -0700 Subject: [PATCH 3/5] Update lib/pliny/error_reporters/sentry.rb Co-authored-by: Troels Thomsen <19824+tt@users.noreply.github.com> --- lib/pliny/error_reporters/sentry.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/pliny/error_reporters/sentry.rb b/lib/pliny/error_reporters/sentry.rb index f8fad8b0..d6c69052 100644 --- a/lib/pliny/error_reporters/sentry.rb +++ b/lib/pliny/error_reporters/sentry.rb @@ -35,11 +35,7 @@ def configure_scope(scope, context:, rack_env:) end def extract_person_data_from_controller(env) - if env.key?("sentry.person_data") - env["sentry.person_data"] || {} - else - {} - end + env["sentry.person_data"] || {} end end end From 449b8b908c1d8f7e0be6b46cda59e35c3c7ae077 Mon Sep 17 00:00:00 2001 From: Daniel Bright Date: Thu, 18 Sep 2025 08:53:43 -0700 Subject: [PATCH 4/5] remove tempate for rollbar --- lib/pliny/error_reporters/sentry.rb | 2 -- lib/template/config/initializers/rollbar.rb | 14 -------------- 2 files changed, 16 deletions(-) delete mode 100644 lib/template/config/initializers/rollbar.rb diff --git a/lib/pliny/error_reporters/sentry.rb b/lib/pliny/error_reporters/sentry.rb index d6c69052..43f11bc4 100644 --- a/lib/pliny/error_reporters/sentry.rb +++ b/lib/pliny/error_reporters/sentry.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require "sentry-ruby" - module Pliny module ErrorReporters class Sentry diff --git a/lib/template/config/initializers/rollbar.rb b/lib/template/config/initializers/rollbar.rb deleted file mode 100644 index 365e584b..00000000 --- a/lib/template/config/initializers/rollbar.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -require "pliny/error_reporters/rollbar" - -Pliny::ErrorReporters.error_reporters << Pliny::ErrorReporters::Rollbar - -Rollbar.configure do |config| - config.enabled = ENV.key?("ROLLBAR_ACCESS_TOKEN") - config.disable_rack_monkey_patch = true - config.access_token = ENV["ROLLBAR_ACCESS_TOKEN"] - config.environment = ENV["ROLLBAR_ENV"] - config.logger = Pliny::RollbarLogger.new - config.use_sucker_punch -end From 985e5a8b1dc891989648df8139601a69de8adc52 Mon Sep 17 00:00:00 2001 From: Daniel Bright Date: Mon, 22 Sep 2025 09:46:38 -0700 Subject: [PATCH 5/5] lint --- spec/error_reporters/sentry_spec.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/error_reporters/sentry_spec.rb b/spec/error_reporters/sentry_spec.rb index 7feca8ab..7f960434 100644 --- a/spec/error_reporters/sentry_spec.rb +++ b/spec/error_reporters/sentry_spec.rb @@ -43,7 +43,6 @@ expect(::Sentry).to have_received(:capture_exception).with(exception) end - context "given a rack_env with sentry.person_data" do let(:rack_env) { { "sentry.person_data" => { id: 123, email: "test@example.com", username: "testuser" }, "rack.input" => StringIO.new } } @@ -80,6 +79,5 @@ expect(::Sentry).to have_received(:capture_exception).with(exception) end end - end -end \ No newline at end of file +end