chore: Upgrade Exception tracking (#4638)

- Upgrade Sentry Libraries
- Enable provision for account and user info in error tracking
- Add ChatwootExceptionTracker

fixes: #4375
pull/4659/head
Sojan Jose 2 years ago committed by GitHub
parent 360b438a55
commit 04dfb034cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -97,9 +97,9 @@ gem 'brakeman'
gem 'ddtrace'
gem 'newrelic_rpm'
gem 'scout_apm'
gem 'sentry-rails'
gem 'sentry-ruby'
gem 'sentry-sidekiq'
gem 'sentry-rails', '~> 5.3'
gem 'sentry-ruby', '~> 5.3'
gem 'sentry-sidekiq', '~> 5.3'
##-- background job processing --##
gem 'sidekiq', '~> 6.4.0'

@ -349,7 +349,7 @@ GEM
listen (3.7.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
loofah (2.16.0)
loofah (2.17.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
@ -378,14 +378,14 @@ GEM
netrc (0.11.0)
newrelic_rpm (8.7.0)
nio4r (2.5.8)
nokogiri (1.13.4)
nokogiri (1.13.5)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
nokogiri (1.13.4-arm64-darwin)
nokogiri (1.13.5-arm64-darwin)
racc (~> 1.4)
nokogiri (1.13.4-x86_64-darwin)
nokogiri (1.13.5-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.13.4-x86_64-linux)
nokogiri (1.13.5-x86_64-linux)
racc (~> 1.4)
oauth (0.5.8)
orm_adapter (0.5.0)
@ -533,16 +533,16 @@ GEM
activesupport (>= 4)
selectize-rails (0.12.6)
semantic_range (3.0.0)
sentry-rails (5.1.0)
sentry-rails (5.3.0)
railties (>= 5.0)
sentry-ruby-core (~> 5.1.0)
sentry-ruby (5.1.0)
sentry-ruby-core (~> 5.3.0)
sentry-ruby (5.3.0)
concurrent-ruby (~> 1.0, >= 1.0.2)
sentry-ruby-core (= 5.1.0)
sentry-ruby-core (5.1.0)
sentry-ruby-core (= 5.3.0)
sentry-ruby-core (5.3.0)
concurrent-ruby
sentry-sidekiq (5.1.0)
sentry-ruby-core (~> 5.1.0)
sentry-sidekiq (5.3.0)
sentry-ruby-core (~> 5.3.0)
sidekiq (>= 3.0)
sexp_processor (4.16.0)
shoulda-matchers (5.1.0)
@ -726,9 +726,9 @@ DEPENDENCIES
rubocop-rspec
scout_apm
seed_dump
sentry-rails
sentry-ruby
sentry-sidekiq
sentry-rails (~> 5.3)
sentry-ruby (~> 5.3)
sentry-sidekiq (~> 5.3)
shoulda-matchers
sidekiq (~> 6.4.0)
sidekiq-cron (~> 1.3)
@ -755,4 +755,4 @@ RUBY VERSION
ruby 3.0.2p107
BUNDLED WITH
2.3.9
2.3.10

@ -29,7 +29,7 @@ class Messages::Facebook::MessageBuilder < Messages::Messenger::MessageBuilder
rescue Koala::Facebook::AuthenticationError
Rails.logger.error "Facebook Authorization expired for Inbox #{@inbox.id}"
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e, account: @inbox.account).capture_exception
true
end
@ -128,10 +128,10 @@ class Messages::Facebook::MessageBuilder < Messages::Messenger::MessageBuilder
result = {}
# OAuthException, code: 100, error_subcode: 2018218, message: (#100) No profile available for this user
# We don't need to capture this error as we don't care about contact params in case of echo messages
Sentry.capture_exception(e) unless @outgoing_echo
ChatwootExceptionTracker.new(e, account: @inbox.account).capture_exception unless @outgoing_echo
rescue StandardError => e
result = {}
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e, account: @inbox.account).capture_exception
end
process_contact_params_result(result)
end

@ -24,7 +24,7 @@ class Messages::Instagram::MessageBuilder < Messages::Messenger::MessageBuilder
@inbox.channel.authorization_error!
raise
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e, account: @inbox.account).capture_exception
true
end

@ -53,16 +53,7 @@ class Messages::Messenger::MessageBuilder
def fetch_story_link(attachment)
message = attachment.message
begin
k = Koala::Facebook::API.new(@inbox.channel.page_access_token) if @inbox.facebook?
result = k.get_object(message.source_id, fields: %w[story from]) || {}
rescue Koala::Facebook::AuthenticationError
@inbox.channel.authorization_error!
raise
rescue StandardError => e
result = {}
Sentry.capture_exception(e)
end
result = get_story_object_from_source_id(message.source_id)
story_id = result['story']['mention']['id']
story_sender = result['from']['username']
message.content_attributes[:story_sender] = story_sender
@ -70,4 +61,15 @@ class Messages::Messenger::MessageBuilder
message.content = I18n.t('conversations.messages.instagram_story_content', story_sender: story_sender)
message.save!
end
def get_story_object_from_source_id(source_id)
k = Koala::Facebook::API.new(@inbox.channel.page_access_token) if @inbox.facebook?
k.get_object(source_id, fields: %w[story from]) || {}
rescue Koala::Facebook::AuthenticationError
@inbox.channel.authorization_error!
raise
rescue StandardError => e
ChatwootExceptionTracker.new(e, account: @inbox.account).capture_exception
{}
end
end

@ -15,7 +15,7 @@ class Api::V1::Accounts::CallbacksController < Api::V1::Accounts::BaseController
set_instagram_id(page_access_token, facebook_channel)
set_avatar(@facebook_inbox, page_id)
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e).capture_exception
end
end
@ -60,7 +60,7 @@ class Api::V1::Accounts::CallbacksController < Api::V1::Accounts::BaseController
set_instagram_id(access_token, fb_page)
fb_page&.reauthorized!
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e).capture_exception
end
end

@ -10,7 +10,7 @@ class Api::V1::WebhooksController < ApplicationController
twitter_consumer.consume
head :ok
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e).capture_exception
head :ok
end

@ -9,8 +9,7 @@ module RequestExceptionHandler
def handle_with_exception
yield
rescue ActiveRecord::RecordNotFound => e
Sentry.capture_exception(e)
rescue ActiveRecord::RecordNotFound
render_not_found_error('Resource could not be found')
rescue Pundit::NotAuthorizedError
render_unauthorized('You are not authorized to do this action')

@ -11,7 +11,7 @@ class Inboxes::FetchImapEmailsJob < ApplicationJob
channel.authorization_error!
rescue StandardError => e
channel.authorization_error!
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e, account: channel.account).capture_exception
end
private

@ -12,7 +12,7 @@ class AutomationRules::ActionService
begin
send(action[:action_name], action[:action_params])
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e, account: @account).capture_exception
end
end
ensure

@ -9,7 +9,7 @@ class Facebook::SendOnFacebookService < Base::SendOnChannelService
send_message_to_facebook fb_text_message_params if message.content.present?
send_message_to_facebook fb_attachment_message_params if message.attachments.present?
rescue Facebook::Messenger::FacebookError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e, account: message.account, user: message.sender).capture_exception
# TODO : handle specific errors or else page will get disconnected
# channel.authorization_error!
end

@ -38,7 +38,7 @@ class Instagram::MessageText < Instagram::WebhooksBaseService
raise
rescue StandardError => e
result = {}
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e, account: @inbox.account).capture_exception
end
find_or_create_contact(result)

@ -17,7 +17,7 @@ class Instagram::SendOnInstagramService < Base::SendOnChannelService
send_to_facebook_page attachament_message_params if message.attachments.present?
send_to_facebook_page message_params
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e, account: message.account, user: message.sender).capture_exception
# TODO : handle specific errors or else page will get disconnected
# channel.authorization_error!
end

@ -7,7 +7,7 @@ class MessageTemplates::Template::EmailCollect
conversation.messages.create!(email_input_box_template_message_params)
end
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e, account: conversation.account).capture_exception
true
end

@ -6,7 +6,7 @@ class MessageTemplates::Template::Greeting
conversation.messages.create!(greeting_message_params)
end
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e, account: conversation.account).capture_exception
true
end

@ -6,7 +6,7 @@ class MessageTemplates::Template::OutOfOffice
conversation.messages.create!(out_of_office_message_params)
end
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e, account: conversation.account).capture_exception
true
end

@ -9,7 +9,7 @@ class Twilio::SendOnTwilioService < Base::SendOnChannelService
begin
twilio_message = client.messages.create(**message_params)
rescue Twilio::REST::TwilioError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e, user: message.sender, account: message.account).capture_exception
end
message.update!(source_id: twilio_message.sid) if twilio_message
end

@ -2,5 +2,14 @@ if ENV['SENTRY_DSN']
Sentry.init do |config|
config.dsn = ENV['SENTRY_DSN']
config.enabled_environments = %w[staging production]
# To activate performance monitoring, set one of these options.
# We recommend adjusting the value in production:
config.traces_sample_rate = 0.1
config.excluded_exceptions += ['Rack::Timeout::RequestTimeoutException']
# to track post data in sentry
config.send_default_pii = true unless ENV['DISABLE_SENTRY_PII']
end
end

@ -0,0 +1,32 @@
###############
# One library to capture_exception and send to the specific service.
# # e as exception, u for user and a for account (user and account are optional)
# Usage: ChatwootExceptionTracker(e, user: u, account: a).capture_exception
############
class ChatwootExceptionTracker
def initialize(exception, user: nil, account: nil)
@exception = exception
@user = user
@account = account
end
def capture_exception
capture_exception_with_sentry if ENV['SENTRY_DSN'].present?
# Implement other providers like honeybadger, rollbar etc in future
end
private
def capture_exception_with_sentry
Sentry.with_scope do |scope|
if @account.present?
scope.set_context('account', { id: @account.id, name: @account.name })
scope.set_tags(account_id: @account.id)
end
scope.set_user(id: @user.id, email: @user.email) if @user.is_a?(User)
Sentry.capture_exception(@exception)
end
end
end

@ -42,7 +42,7 @@ class ChatwootHub
rescue *ExceptionList::REST_CLIENT_EXCEPTIONS => e
Rails.logger.error "Exception: #{e.message}"
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e).capture_exception
end
version
end
@ -53,7 +53,7 @@ class ChatwootHub
rescue *ExceptionList::REST_CLIENT_EXCEPTIONS => e
Rails.logger.error "Exception: #{e.message}"
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e).capture_exception
end
def self.send_browser_push(fcm_token_list, fcm_options)
@ -62,7 +62,7 @@ class ChatwootHub
rescue *ExceptionList::REST_CLIENT_EXCEPTIONS => e
Rails.logger.error "Exception: #{e.message}"
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e).capture_exception
end
def self.emit_event(event_name, event_data)
@ -73,6 +73,6 @@ class ChatwootHub
rescue *ExceptionList::REST_CLIENT_EXCEPTIONS => e
Rails.logger.error "Exception: #{e.message}"
rescue StandardError => e
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e).capture_exception
end
end

@ -15,7 +15,7 @@ class Integrations::Facebook::MessageCreator
create_contact_message
end
# rescue => e
# Sentry.capture_exception(e)
# ChatwootExceptionTracker.new(e).capture_exception
# end
end

@ -11,6 +11,6 @@ class Webhooks::Trigger
Rails.logger.error "Exception: invalid webhook url #{url} : #{e.message}"
rescue StandardError => e
Rails.logger.error "Exception: invalid webhook url #{url} : #{e.message}"
Sentry.capture_exception(e)
ChatwootExceptionTracker.new(e).capture_exception
end
end

@ -23,8 +23,8 @@
"@hcaptcha/vue-hcaptcha": "^0.3.2",
"@rails/actioncable": "6.1.3",
"@rails/webpacker": "5.3.0",
"@sentry/tracing": "^6.4.1",
"@sentry/vue": "^6.4.1",
"@sentry/tracing": "^6.19.7",
"@sentry/vue": "^6.19.7",
"activestorage": "^5.2.6",
"axios": "^0.21.2",
"babel-plugin-syntax-jsx": "^6.18.0",

@ -0,0 +1,23 @@
require 'rails_helper'
describe ChatwootExceptionTracker do
it 'returns nil if no tracker is configured' do
expect(described_class.new('random').capture_exception).to eq(nil)
end
context 'with sentry DSN' do
before do
# since sentry is not initated in test, we need to do it manually
Sentry.init do |config|
config.dsn = 'test'
end
end
it 'will call sentry capture exception' do
with_modified_env SENTRY_DSN: 'random dsn' do
expect(Sentry).to receive(:capture_exception).with('random')
described_class.new('random').capture_exception
end
end
end
end

@ -1688,84 +1688,84 @@
dependencies:
any-observable "^0.3.0"
"@sentry/browser@6.4.1":
version "6.4.1"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.4.1.tgz#b6c62736caaade7fdf6638513d9aad138abde2ac"
integrity sha512-3cDud6GWutnJqcnheIq0lPNTsUJbrRLevQ+g1YfawVXFUxfmmY2bOsGd/Mxq17LxYeBHgKTitXv3DU1bsQ+WBQ==
dependencies:
"@sentry/core" "6.4.1"
"@sentry/types" "6.4.1"
"@sentry/utils" "6.4.1"
"@sentry/browser@6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.19.7.tgz#a40b6b72d911b5f1ed70ed3b4e7d4d4e625c0b5f"
integrity sha512-oDbklp4O3MtAM4mtuwyZLrgO1qDVYIujzNJQzXmi9YzymJCuzMLSRDvhY83NNDCRxf0pds4DShgYeZdbSyKraA==
dependencies:
"@sentry/core" "6.19.7"
"@sentry/types" "6.19.7"
"@sentry/utils" "6.19.7"
tslib "^1.9.3"
"@sentry/core@6.4.1":
version "6.4.1"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.4.1.tgz#789b0071996de5c1a20673f879408926aa3b4fa6"
integrity sha512-Lx13oTiP+Tjvm5VxulcCszNVd2S1wY4viSnr+ygq62ySVERR+t7uOZDSARZ0rZ259GwW6nkbMh9dDmD0d6VCGQ==
"@sentry/core@6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.19.7.tgz#156aaa56dd7fad8c89c145be6ad7a4f7209f9785"
integrity sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==
dependencies:
"@sentry/hub" "6.4.1"
"@sentry/minimal" "6.4.1"
"@sentry/types" "6.4.1"
"@sentry/utils" "6.4.1"
"@sentry/hub" "6.19.7"
"@sentry/minimal" "6.19.7"
"@sentry/types" "6.19.7"
"@sentry/utils" "6.19.7"
tslib "^1.9.3"
"@sentry/hub@6.4.1":
version "6.4.1"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.4.1.tgz#fa9c05ca32674e2e8477120b71084a1c91a5e023"
integrity sha512-7IZRP5buDE6s/c3vWzzPR/ySE+8GUuHPgTEPiDCPOCWwUN11zXDafJDKkJqY3muJfebUKmC/JG67RyBx+XlnlQ==
"@sentry/hub@6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.19.7.tgz#58ad7776bbd31e9596a8ec46365b45cd8b9cfd11"
integrity sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==
dependencies:
"@sentry/types" "6.4.1"
"@sentry/utils" "6.4.1"
"@sentry/types" "6.19.7"
"@sentry/utils" "6.19.7"
tslib "^1.9.3"
"@sentry/minimal@6.4.1":
version "6.4.1"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.4.1.tgz#d3f968c060c3d3cc997071756659e24047b5dd97"
integrity sha512-4x/PRbDZACCKJqjta9EkhiIMyGMf7VgBX13EEWEDVWLP7ymFukBuTr4ap/Tz9429kB/yXZuDGGMIZp/G618H3g==
"@sentry/minimal@6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.19.7.tgz#b3ee46d6abef9ef3dd4837ebcb6bdfd01b9aa7b4"
integrity sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==
dependencies:
"@sentry/hub" "6.4.1"
"@sentry/types" "6.4.1"
"@sentry/hub" "6.19.7"
"@sentry/types" "6.19.7"
tslib "^1.9.3"
"@sentry/tracing@^6.4.1":
version "6.4.1"
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.4.1.tgz#3a9119e1ef5206ea565854c325b19a317cc1cca7"
integrity sha512-EPRadE9n/wpUjx4jqP/8vXdOAZBk7vjlzRKniJgKgQUO3v03i0ui6xydaal2mvhplIyOCI2muXdGhjUO7ga4uw==
"@sentry/tracing@^6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.19.7.tgz#54bb99ed5705931cd33caf71da347af769f02a4c"
integrity sha512-ol4TupNnv9Zd+bZei7B6Ygnr9N3Gp1PUrNI761QSlHtPC25xXC5ssSD3GMhBgyQrcvpuRcCFHVNNM97tN5cZiA==
dependencies:
"@sentry/hub" "6.4.1"
"@sentry/minimal" "6.4.1"
"@sentry/types" "6.4.1"
"@sentry/utils" "6.4.1"
"@sentry/hub" "6.19.7"
"@sentry/minimal" "6.19.7"
"@sentry/types" "6.19.7"
"@sentry/utils" "6.19.7"
tslib "^1.9.3"
"@sentry/types@6.4.1":
version "6.4.1"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.4.1.tgz#7c0a4355a1d04321b901197723a8f55c263226e9"
integrity sha512-sTu/GaLsLYk1AkAqpkMT4+4q665LtZjhV0hkgiTD4N3zPl5uSf1pCIzxPRYjOpe7NEANmWv8U4PaGKGtc2eMfA==
"@sentry/types@6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.7.tgz#c6b337912e588083fc2896eb012526cf7cfec7c7"
integrity sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==
"@sentry/types@^6.11.0":
version "6.12.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.12.0.tgz#b7395688a79403c6df8d8bb8d81deb8222519853"
integrity sha512-urtgLzE4EDMAYQHYdkgC0Ei9QvLajodK1ntg71bGn0Pm84QUpaqpPDfHRU+i6jLeteyC7kWwa5O5W1m/jrjGXA==
"@sentry/utils@6.4.1":
version "6.4.1"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.4.1.tgz#55fa7da58898773cbd538e4895fc2e4ec695ecab"
integrity sha512-xJ1uVa5fvg23pXQfulvCIBb9pQ3p1awyd1PapK2AYi+wKjTuYl4B9edmhjRREEQEExznl/d2OVm78fRXLq7M9Q==
"@sentry/utils@6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.19.7.tgz#6edd739f8185fd71afe49cbe351c1bbf5e7b7c79"
integrity sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==
dependencies:
"@sentry/types" "6.4.1"
"@sentry/types" "6.19.7"
tslib "^1.9.3"
"@sentry/vue@^6.4.1":
version "6.4.1"
resolved "https://registry.yarnpkg.com/@sentry/vue/-/vue-6.4.1.tgz#776a05be1accf251ec7c74d01be0bba57ff995a9"
integrity sha512-Bq7HVbhXqcJlVd9cLs4gnCi+mwPksZ0K4E7w6ZZH1jpNYVziymL5EdhM28o83aD4YfgxEf3PHnOLBmfLfg7izA==
dependencies:
"@sentry/browser" "6.4.1"
"@sentry/core" "6.4.1"
"@sentry/minimal" "6.4.1"
"@sentry/types" "6.4.1"
"@sentry/utils" "6.4.1"
"@sentry/vue@^6.19.7":
version "6.19.7"
resolved "https://registry.yarnpkg.com/@sentry/vue/-/vue-6.19.7.tgz#3f3a880caef777a79fd1e2245768979642cf6885"
integrity sha512-TW2yrbNebpWDN9CcQQuDNWZ3BCM/noDS1jz91W0bcsaAeoZwG0xgcHZqFwL+ms0G/yQmRc2Joe0fKPYp03IBGg==
dependencies:
"@sentry/browser" "6.19.7"
"@sentry/core" "6.19.7"
"@sentry/minimal" "6.19.7"
"@sentry/types" "6.19.7"
"@sentry/utils" "6.19.7"
tslib "^1.9.3"
"@sinonjs/commons@^1.7.0":

Loading…
Cancel
Save