From c9a8aa5d0833538b3f81a7e6d43e6cfcc5337f7b Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 9 Jun 2021 12:54:31 -0500 Subject: [PATCH] Add Sentry Capture in #panic and a few other places, add customer and route context as well as some initial breadcrumbs in the register command. --- Gemfile | 1 + sgx_jmp.rb | 63 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/Gemfile b/Gemfile index 5152fb8..d9bea8a 100644 --- a/Gemfile +++ b/Gemfile @@ -13,6 +13,7 @@ gem "em_promise.rb", "~> 0.0.2" gem "eventmachine" gem "money-open-exchange-rates" gem "ruby-bandwidth-iris" +gem "sentry-ruby" group(:development) do gem "pry-reload" diff --git a/sgx_jmp.rb b/sgx_jmp.rb index 0419103..72e2cbc 100644 --- a/sgx_jmp.rb +++ b/sgx_jmp.rb @@ -10,6 +10,9 @@ require "dhall" require "em-hiredis" require "em_promise" require "ruby-bandwidth-iris" +require "sentry-ruby" + +Sentry.init CONFIG = Dhall::Coder @@ -42,6 +45,17 @@ BandwidthIris::Client.global_options = { password: CONFIG[:creds][:password] } +def new_sentry_hub(stanza, name: nil) + hub = Sentry.get_current_hub&.new_from_top + raise "Sentry.init has not been called" unless hub + + hub.push_scope + hub.current_scope.clear_breadcrumbs + hub.current_scope.set_transaction_name(name) if name + hub.current_scope.set_user(jid: stanza.from.stripped.to_s) + hub +end + # Braintree is not async, so wrap in EM.defer for now class AsyncBraintree def initialize(environment:, merchant_id:, public_key:, private_key:, **) @@ -79,10 +93,15 @@ end BRAINTREE = AsyncBraintree.new(**CONFIG[:braintree]) -def panic(e) +def panic(e, hub=nil) m = e.respond_to?(:message) ? e.message : e warn "Error raised during event loop: #{e.class}: #{m}" warn e.backtrace if e.respond_to?(:backtrace) + if e.is_a?(::Exception) + (hub || Sentry).capture_exception(e, hint: { background: false }) + else + (hub || Sentry).capture_message(e, hint: { background: false }) + end exit 1 end @@ -121,13 +140,25 @@ message to: /\Aaccount@/ do |m| end message to: /\Acustomer_/, from: /@#{CONFIG[:sgx]}(\/|\Z)/ do |m| + sentry_hub = new_sentry_hub(iq, name: iq.node) Customer.for_customer_id( m.to.node.delete_prefix("customer_") - ).then { |customer| customer.stanza_to(m) }.catch(&method(:panic)) + ).then { |customer| + sentry_hub.current_scope.set_user( + id: customer.customer_id, + jid: iq.from.stripped.to_s + ) + customer.stanza_to(m) + }.catch { |e| panic(e, sentry_hub) } end message do |m| + sentry_hub = new_sentry_hub(iq, name: iq.node) Customer.for_jid(m.from.stripped).then { |customer| + sentry_hub.current_scope.set_user( + id: customer.customer_id, + jid: iq.from.stripped.to_s + ) today = Time.now.utc.to_date EMPromise.all([ REDIS.zremrangebylex( @@ -143,7 +174,7 @@ message do |m| ), customer.stanza_from(m) ]) - }.catch(&method(:panic)) + }.catch { |e| panic(e, sentry_hub) } end message :error? do |m| @@ -228,15 +259,28 @@ disco_items node: "http://jabber.org/protocol/commands" do |iq| end command :execute?, node: "jabber:iq:register", sessionid: nil do |iq| - Customer.for_jid(iq.from.stripped).catch { + sentry_hub = new_sentry_hub(iq, name: iq.node) + EMPromise.resolve(nil).then { + Customer.for_jid(iq.from.stripped) + }.catch { + sentry_hub.add_breadcrumb(Sentry::Breadcrumb.new( + message: "Customer.create" + )) Customer.create(iq.from.stripped) }.then { |customer| + sentry_hub.current_scope.set_user( + id: customer.customer_id, + jid: iq.from.stripped.to_s + ) + sentry_hub.add_breadcrumb(Sentry::Breadcrumb.new( + message: "Registration.for" + )) Registration.for( iq, customer, web_register_manager ).then(&:write) - }.catch(&method(:panic)) + }.catch { |e| panic(e, sentry_hub) } end def reply_with_note(iq, text, type: :info) @@ -249,6 +293,7 @@ def reply_with_note(iq, text, type: :info) end command :execute?, node: "buy-credit", sessionid: nil do |iq| + sentry_hub = new_sentry_hub(iq, name: iq.node) reply = iq.reply reply.allowed_actions = [:complete] @@ -265,12 +310,14 @@ command :execute?, node: "buy-credit", sessionid: nil do |iq| }.then { |amount| reply_with_note(iq, "$#{'%.2f' % amount} added to your account balance.") }.catch { |e| + sentry_hub.capture_exception(e) text = "Failed to buy credit, system said: #{e.message}" reply_with_note(iq, text, type: :error) - }.catch(&method(:panic)) + }.catch { |e| panic(e, sentry_hub) } end command :execute?, node: "web-register", sessionid: nil do |iq| + sentry_hub = new_sentry_hub(iq, name: iq.node) jid = iq.form.field("jid")&.value.to_s.strip tel = iq.form.field("tel")&.value.to_s.strip if iq.from.stripped != CONFIG[:web_register][:from] @@ -284,11 +331,11 @@ command :execute?, node: "web-register", sessionid: nil do |iq| cmd.node = "push-register" cmd.form.fields = [var: "to", value: jid] cmd.form.type = "submit" - }).then do |result| + }).then { |result| final_jid = result.form.field("from")&.value.to_s.strip web_register_manager[final_jid] = tel BLATHER << iq.reply.tap { |reply| reply.status = :completed } - end + }.catch { |e| panic(e, sentry_hub) } end end -- 2.45.2