rollbar 2.8.3 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.codeclimate.yml +18 -0
- data/.github/pull_request_template.md +34 -0
- data/.github/workflows/ci.yml +67 -0
- data/.gitignore +3 -1
- data/.rubocop.yml +206 -7
- data/Appraisals +10 -10
- data/CHANGELOG.md +257 -3
- data/Gemfile +74 -13
- data/README.md +38 -833
- data/Rakefile +0 -0
- data/THANKS.md +1 -0
- data/data/rollbar.snippet.js +1 -1
- data/docs/configuration.md +64 -3
- data/docs/plugins.md +46 -0
- data/gemfiles/rails50.gemfile +56 -0
- data/gemfiles/rails51.gemfile +57 -0
- data/gemfiles/rails52.gemfile +56 -0
- data/gemfiles/rails60.gemfile +52 -0
- data/gemfiles/rails61.gemfile +52 -0
- data/gemfiles/rails70.gemfile +52 -0
- data/gemfiles/rails71.gemfile +52 -0
- data/lib/generators/rollbar/rollbar_generator.rb +24 -20
- data/lib/generators/rollbar/templates/{initializer.rb → initializer.erb} +19 -5
- data/lib/rails/rollbar_runner.rb +26 -22
- data/lib/rollbar/capistrano.rb +78 -38
- data/lib/rollbar/capistrano3.rb +62 -1
- data/lib/rollbar/capistrano_tasks.rb +166 -0
- data/lib/rollbar/configuration.rb +291 -71
- data/lib/rollbar/delay/active_job.rb +17 -0
- data/lib/rollbar/delay/delayed_job.rb +23 -0
- data/lib/rollbar/delay/girl_friday.rb +4 -9
- data/lib/rollbar/delay/resque.rb +3 -6
- data/lib/rollbar/delay/shoryuken.rb +36 -0
- data/lib/rollbar/delay/sidekiq.rb +6 -8
- data/lib/rollbar/delay/sucker_punch.rb +17 -22
- data/lib/rollbar/delay/thread.rb +74 -3
- data/lib/rollbar/deploy.rb +91 -0
- data/lib/rollbar/encoding/encoder.rb +22 -11
- data/lib/rollbar/encoding.rb +2 -7
- data/lib/rollbar/exception_reporter.rb +36 -12
- data/lib/rollbar/item/backtrace.rb +118 -0
- data/lib/rollbar/item/frame.rb +121 -0
- data/lib/rollbar/item/locals.rb +103 -0
- data/lib/rollbar/item.rb +314 -0
- data/lib/rollbar/js.rb +0 -28
- data/lib/rollbar/json.rb +7 -55
- data/lib/rollbar/language_support.rb +7 -19
- data/lib/rollbar/lazy_store.rb +8 -12
- data/lib/rollbar/logger.rb +71 -0
- data/lib/rollbar/logger_proxy.rb +18 -1
- data/lib/rollbar/middleware/js/json_value.rb +36 -0
- data/lib/rollbar/middleware/js.rb +297 -0
- data/lib/rollbar/middleware/rack/builder.rb +4 -4
- data/lib/rollbar/middleware/rack/test_session.rb +4 -4
- data/lib/rollbar/middleware/rack.rb +52 -0
- data/lib/rollbar/middleware/rails/rollbar.rb +19 -7
- data/lib/rollbar/middleware/rails/show_exceptions.rb +21 -9
- data/lib/rollbar/middleware/sinatra.rb +2 -40
- data/lib/rollbar/notifier/trace_with_bindings.rb +75 -0
- data/lib/rollbar/notifier.rb +913 -0
- data/lib/rollbar/plugin.rb +126 -0
- data/lib/rollbar/plugins/active_job.rb +54 -0
- data/lib/rollbar/plugins/basic_socket.rb +31 -0
- data/lib/rollbar/plugins/delayed_job/job_data.rb +50 -0
- data/lib/rollbar/plugins/delayed_job/plugin.rb +88 -0
- data/lib/rollbar/plugins/delayed_job.rb +12 -0
- data/lib/rollbar/plugins/error_context.rb +11 -0
- data/lib/rollbar/plugins/goalie.rb +65 -0
- data/lib/rollbar/plugins/rack.rb +18 -0
- data/lib/rollbar/plugins/rails/controller_methods.rb +56 -0
- data/lib/rollbar/plugins/rails/error_subscriber.rb +12 -0
- data/lib/rollbar/plugins/rails/railtie30.rb +18 -0
- data/lib/rollbar/plugins/rails/railtie32.rb +18 -0
- data/lib/rollbar/plugins/rails/railtie_mixin.rb +37 -0
- data/lib/rollbar/plugins/rails.rb +89 -0
- data/lib/rollbar/plugins/rake.rb +73 -0
- data/lib/rollbar/plugins/resque/failure.rb +39 -0
- data/lib/rollbar/plugins/resque.rb +11 -0
- data/lib/rollbar/plugins/sidekiq/plugin.rb +77 -0
- data/lib/rollbar/plugins/sidekiq.rb +37 -0
- data/lib/rollbar/plugins/thread.rb +14 -0
- data/lib/rollbar/plugins/validations.rb +45 -0
- data/lib/rollbar/plugins.rb +47 -0
- data/lib/rollbar/rails.rb +0 -1
- data/lib/rollbar/rake_tasks.rb +4 -66
- data/lib/rollbar/request_data_extractor.rb +157 -117
- data/lib/rollbar/rollbar_test.rb +38 -0
- data/lib/rollbar/scrubbers/params.rb +133 -0
- data/lib/rollbar/scrubbers/url.rb +90 -35
- data/lib/rollbar/scrubbers.rb +13 -0
- data/lib/rollbar/truncation/frames_strategy.rb +2 -1
- data/lib/rollbar/truncation/min_body_strategy.rb +3 -4
- data/lib/rollbar/truncation/mixin.rb +1 -1
- data/lib/rollbar/truncation/remove_any_key_strategy.rb +126 -0
- data/lib/rollbar/truncation/remove_extra_strategy.rb +37 -0
- data/lib/rollbar/truncation/remove_request_strategy.rb +21 -0
- data/lib/rollbar/truncation/strings_strategy.rb +6 -5
- data/lib/rollbar/truncation.rb +10 -4
- data/lib/rollbar/util/hash.rb +37 -6
- data/lib/rollbar/util/ip_anonymizer.rb +33 -0
- data/lib/rollbar/util/ip_obfuscator.rb +1 -1
- data/lib/rollbar/util.rb +101 -55
- data/lib/rollbar/version.rb +1 -1
- data/lib/rollbar.rb +91 -879
- data/lib/tasks/benchmark.rake +104 -0
- data/lib/tasks/tasks.rake +3 -3
- data/rollbar.gemspec +21 -32
- data/spec/support/rollbar_api.rb +67 -0
- metadata +78 -439
- data/.travis.yml +0 -155
- data/gemfiles/rails30.gemfile +0 -20
- data/gemfiles/rails31.gemfile +0 -16
- data/gemfiles/rails32.gemfile +0 -17
- data/gemfiles/rails40.gemfile +0 -17
- data/gemfiles/rails41.gemfile +0 -15
- data/gemfiles/rails42.gemfile +0 -15
- data/lib/rollbar/active_job.rb +0 -11
- data/lib/rollbar/active_record_extension.rb +0 -14
- data/lib/rollbar/core_ext/basic_socket.rb +0 -7
- data/lib/rollbar/core_ext/thread.rb +0 -9
- data/lib/rollbar/delayed_job.rb +0 -78
- data/lib/rollbar/encoding/legacy_encoder.rb +0 -20
- data/lib/rollbar/goalie.rb +0 -33
- data/lib/rollbar/js/frameworks/rails.rb +0 -29
- data/lib/rollbar/js/frameworks.rb +0 -6
- data/lib/rollbar/js/middleware.rb +0 -129
- data/lib/rollbar/js/version.rb +0 -5
- data/lib/rollbar/json/default.rb +0 -11
- data/lib/rollbar/json/oj.rb +0 -15
- data/lib/rollbar/rack.rb +0 -9
- data/lib/rollbar/rails/controller_methods.rb +0 -40
- data/lib/rollbar/railtie.rb +0 -46
- data/lib/rollbar/rake.rb +0 -38
- data/lib/rollbar/sidekiq.rb +0 -40
- data/lib/rollbar/tasks/rollbar.cap +0 -45
- data/spec/cacert.pem +0 -3988
- data/spec/controllers/home_controller_spec.rb +0 -455
- data/spec/delay/sidekiq_spec.rb +0 -61
- data/spec/delay/sucker_punch_spec.rb +0 -25
- data/spec/delayed/backend/test.rb +0 -139
- data/spec/delayed/serialization/test.rb +0 -0
- data/spec/dummyapp/.gitignore +0 -73
- data/spec/dummyapp/Rakefile +0 -7
- data/spec/dummyapp/app/assets/javascripts/application.js +0 -3
- data/spec/dummyapp/app/assets/stylesheets/application.css.scss +0 -37
- data/spec/dummyapp/app/controllers/application_controller.rb +0 -3
- data/spec/dummyapp/app/controllers/home_controller.rb +0 -60
- data/spec/dummyapp/app/controllers/users_controller.rb +0 -17
- data/spec/dummyapp/app/helpers/.gitkeep +0 -0
- data/spec/dummyapp/app/mailers/.gitkeep +0 -0
- data/spec/dummyapp/app/models/.gitkeep +0 -0
- data/spec/dummyapp/app/models/user.rb +0 -7
- data/spec/dummyapp/app/views/devise/registrations/edit.html.erb +0 -27
- data/spec/dummyapp/app/views/devise/registrations/new.html.erb +0 -20
- data/spec/dummyapp/app/views/devise/shared/_links.html.erb +0 -25
- data/spec/dummyapp/app/views/home/cause_exception.html.erb +0 -1
- data/spec/dummyapp/app/views/home/index.html.erb +0 -4
- data/spec/dummyapp/app/views/home/report_exception.html.erb +0 -1
- data/spec/dummyapp/app/views/js/test.html.erb +0 -1
- data/spec/dummyapp/app/views/layouts/_messages.html.erb +0 -5
- data/spec/dummyapp/app/views/layouts/_navigation.html.erb +0 -21
- data/spec/dummyapp/app/views/layouts/application.html.erb +0 -25
- data/spec/dummyapp/app/views/layouts/simple.html.erb +0 -18
- data/spec/dummyapp/app/views/users/index.html.erb +0 -8
- data/spec/dummyapp/app/views/users/show.html.erb +0 -3
- data/spec/dummyapp/config/application.rb +0 -59
- data/spec/dummyapp/config/boot.rb +0 -10
- data/spec/dummyapp/config/database.yml +0 -25
- data/spec/dummyapp/config/environment.rb +0 -5
- data/spec/dummyapp/config/environments/development.rb +0 -37
- data/spec/dummyapp/config/environments/production.rb +0 -67
- data/spec/dummyapp/config/environments/test.rb +0 -37
- data/spec/dummyapp/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/dummyapp/config/initializers/inflections.rb +0 -15
- data/spec/dummyapp/config/initializers/mime_types.rb +0 -5
- data/spec/dummyapp/config/initializers/rollbar.rb +0 -23
- data/spec/dummyapp/config/initializers/secret_token.rb +0 -7
- data/spec/dummyapp/config/initializers/session_store.rb +0 -8
- data/spec/dummyapp/config/initializers/wrap_parameters.rb +0 -16
- data/spec/dummyapp/config/locales/devise.en.yml +0 -58
- data/spec/dummyapp/config/locales/en.yml +0 -5
- data/spec/dummyapp/config/routes.rb +0 -17
- data/spec/dummyapp/config.ru +0 -4
- data/spec/dummyapp/db/migrate/20121121184652_devise_create_users.rb +0 -46
- data/spec/dummyapp/db/migrate/20121121184654_add_name_to_users.rb +0 -5
- data/spec/dummyapp/db/schema.rb +0 -35
- data/spec/dummyapp/db/seeds.rb +0 -12
- data/spec/dummyapp/lib/assets/.gitkeep +0 -0
- data/spec/dummyapp/public/404.html +0 -26
- data/spec/dummyapp/public/422.html +0 -26
- data/spec/dummyapp/public/500.html +0 -25
- data/spec/dummyapp/public/favicon.ico +0 -0
- data/spec/dummyapp/script/rails +0 -6
- data/spec/fixtures/file1 +0 -1
- data/spec/fixtures/file2 +0 -1
- data/spec/fixtures/payloads/message.json +0 -25
- data/spec/fixtures/payloads/sample.trace.json +0 -275
- data/spec/fixtures/payloads/sample.trace_chain.json +0 -530
- data/spec/generators/rollbar/rollbar_generator_spec.rb +0 -24
- data/spec/requests/home_spec.rb +0 -49
- data/spec/rollbar/active_job_spec.rb +0 -33
- data/spec/rollbar/configuration_spec.rb +0 -24
- data/spec/rollbar/delay/girl_friday_spec.rb +0 -41
- data/spec/rollbar/delay/resque_spec.rb +0 -37
- data/spec/rollbar/delay/thread_spec.rb +0 -27
- data/spec/rollbar/delayed_job/job_data.rb +0 -35
- data/spec/rollbar/delayed_job_spec.rb +0 -90
- data/spec/rollbar/encoding/encoder_spec.rb +0 -63
- data/spec/rollbar/js/frameworks/rails_spec.rb +0 -19
- data/spec/rollbar/js/middleware_spec.rb +0 -162
- data/spec/rollbar/json/oj_spec.rb +0 -18
- data/spec/rollbar/json_spec.rb +0 -110
- data/spec/rollbar/lazy_store_spec.rb +0 -99
- data/spec/rollbar/logger_proxy_spec.rb +0 -34
- data/spec/rollbar/middleware/rack/builder_spec.rb +0 -151
- data/spec/rollbar/middleware/sinatra_spec.rb +0 -197
- data/spec/rollbar/rake_spec.rb +0 -34
- data/spec/rollbar/request_data_extractor_spec.rb +0 -82
- data/spec/rollbar/scrubbers/url_spec.rb +0 -111
- data/spec/rollbar/sidekiq_spec.rb +0 -90
- data/spec/rollbar/truncation/frames_strategy_spec.rb +0 -70
- data/spec/rollbar/truncation/min_body_strategy_spec.rb +0 -57
- data/spec/rollbar/truncation/strings_strategy_spec.rb +0 -89
- data/spec/rollbar/truncation_spec.rb +0 -27
- data/spec/rollbar/util/hash_spec.rb +0 -22
- data/spec/rollbar/util_spec.rb +0 -19
- data/spec/rollbar_bc_spec.rb +0 -380
- data/spec/rollbar_spec.rb +0 -2067
- data/spec/spec_helper.rb +0 -49
- data/spec/support/cause_exception.rb +0 -1
- data/spec/support/encoding_helpers.rb +0 -8
- data/spec/support/encodings/iso_8859_9 +0 -1
- data/spec/support/fixture_helpers.rb +0 -10
- data/spec/support/get_ip_raising.rb +0 -7
- data/spec/support/helpers.rb +0 -5
- data/spec/support/notifier_helpers.rb +0 -36
- data/spec/support/shared_contexts.rb +0 -12
@@ -0,0 +1,913 @@
|
|
1
|
+
require 'rollbar/configuration'
|
2
|
+
require 'rollbar/lazy_store'
|
3
|
+
require 'rollbar/util'
|
4
|
+
require 'rollbar/json'
|
5
|
+
require 'rollbar/exceptions'
|
6
|
+
require 'rollbar/language_support'
|
7
|
+
require 'rollbar/delay/girl_friday'
|
8
|
+
require 'rollbar/delay/thread'
|
9
|
+
require 'rollbar/logger_proxy'
|
10
|
+
require 'rollbar/item'
|
11
|
+
require 'rollbar/notifier/trace_with_bindings'
|
12
|
+
require 'ostruct'
|
13
|
+
|
14
|
+
module Rollbar
|
15
|
+
# The notifier class. It has the core functionality
|
16
|
+
# for sending reports to the API.
|
17
|
+
class Notifier
|
18
|
+
attr_accessor :configuration, :last_report, :scope_object
|
19
|
+
|
20
|
+
MUTEX = Mutex.new
|
21
|
+
EXTENSION_REGEXP = /.rollbar\z/.freeze
|
22
|
+
FAILSAFE_STRING_LENGTH = 10_000
|
23
|
+
|
24
|
+
def initialize(parent_notifier = nil, payload_options = nil, scope = nil)
|
25
|
+
if parent_notifier
|
26
|
+
self.configuration = parent_notifier.configuration.clone
|
27
|
+
self.scope_object = parent_notifier.scope_object.clone
|
28
|
+
|
29
|
+
Rollbar::Util.deep_merge(scope_object, scope) if scope
|
30
|
+
else
|
31
|
+
self.configuration = ::Rollbar::Configuration.new
|
32
|
+
self.scope_object = ::Rollbar::LazyStore.new(scope)
|
33
|
+
end
|
34
|
+
|
35
|
+
return unless payload_options
|
36
|
+
|
37
|
+
Rollbar::Util.deep_merge(configuration.payload_options, payload_options)
|
38
|
+
end
|
39
|
+
|
40
|
+
def reset!
|
41
|
+
self.scope_object = ::Rollbar::LazyStore.new({})
|
42
|
+
end
|
43
|
+
|
44
|
+
# Similar to configure below, but used only internally within the gem
|
45
|
+
# to configure it without initializing any of the third party hooks
|
46
|
+
def preconfigure
|
47
|
+
yield(configuration.configured_options)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Configures the notifier instance
|
51
|
+
def configure
|
52
|
+
configuration.enabled = true if configuration.enabled.nil?
|
53
|
+
|
54
|
+
yield(configuration.configured_options)
|
55
|
+
end
|
56
|
+
|
57
|
+
def reconfigure
|
58
|
+
self.configuration = Configuration.new
|
59
|
+
configuration.enabled = true
|
60
|
+
|
61
|
+
yield(configuration.configured_options)
|
62
|
+
end
|
63
|
+
|
64
|
+
def unconfigure
|
65
|
+
self.configuration = nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def scope(scope_overrides = {}, config_overrides = {})
|
69
|
+
new_notifier = self.class.new(self, nil, scope_overrides)
|
70
|
+
new_notifier.configuration = configuration.merge(config_overrides)
|
71
|
+
|
72
|
+
new_notifier
|
73
|
+
end
|
74
|
+
|
75
|
+
def scope!(options = {}, config_overrides = {})
|
76
|
+
Rollbar::Util.deep_merge(scope_object, options)
|
77
|
+
configuration.merge!(config_overrides)
|
78
|
+
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns a new notifier with same configuration options
|
83
|
+
# but it sets Configuration#safely to true.
|
84
|
+
# We are using this flag to avoid having inifite loops
|
85
|
+
# when evaluating some custom user methods.
|
86
|
+
def safely
|
87
|
+
new_notifier = scope
|
88
|
+
new_notifier.configuration.safely = true
|
89
|
+
|
90
|
+
new_notifier
|
91
|
+
end
|
92
|
+
|
93
|
+
# Turns off reporting for the given block.
|
94
|
+
#
|
95
|
+
# @example
|
96
|
+
# Rollbar.silenced { raise }
|
97
|
+
#
|
98
|
+
# @yield Block which exceptions won't be reported.
|
99
|
+
def silenced
|
100
|
+
yield
|
101
|
+
rescue StandardError => e
|
102
|
+
e.instance_variable_set(:@_rollbar_do_not_report, true)
|
103
|
+
raise
|
104
|
+
end
|
105
|
+
|
106
|
+
# Sends a report to Rollbar.
|
107
|
+
#
|
108
|
+
# Accepts a level string plus any number of arguments. The last String
|
109
|
+
# argument will become the message or description of the report. The last
|
110
|
+
# Exception argument will become the associated exception for the report.
|
111
|
+
# The last hash argument will be used as the extra data for the report.
|
112
|
+
#
|
113
|
+
# If the extra hash contains a symbol key :custom_data_method_context
|
114
|
+
# the value of the key will be used as the context for
|
115
|
+
# configuration.custom_data_method and will be removed from the extra
|
116
|
+
# hash.
|
117
|
+
#
|
118
|
+
# @example
|
119
|
+
# begin
|
120
|
+
# foo = bar
|
121
|
+
# rescue => e
|
122
|
+
# Rollbar.log('error', e)
|
123
|
+
# end
|
124
|
+
#
|
125
|
+
# @example
|
126
|
+
# Rollbar.log('info', 'This is a simple log message')
|
127
|
+
#
|
128
|
+
# @example
|
129
|
+
# Rollbar.log('error', e, 'This is a description of the exception')
|
130
|
+
#
|
131
|
+
def log(level, *args)
|
132
|
+
return 'disabled' unless enabled?
|
133
|
+
|
134
|
+
message, exception, extra, context = extract_arguments(args)
|
135
|
+
use_exception_level_filters = use_exception_level_filters?(extra)
|
136
|
+
|
137
|
+
return 'ignored' if ignored?(exception, use_exception_level_filters) ||
|
138
|
+
ignore_before_process?(level, exception, message, extra)
|
139
|
+
|
140
|
+
level = lookup_exception_level(level, exception,
|
141
|
+
use_exception_level_filters)
|
142
|
+
|
143
|
+
ret = report_with_rescue(level, message, exception, extra, context)
|
144
|
+
|
145
|
+
raise(exception) if configuration.raise_on_error && exception
|
146
|
+
|
147
|
+
ret
|
148
|
+
end
|
149
|
+
|
150
|
+
def ignore_before_process?(level, exception, message, extra)
|
151
|
+
status = call_before_process(:level => level,
|
152
|
+
:exception => exception,
|
153
|
+
:message => message,
|
154
|
+
:extra => extra)
|
155
|
+
|
156
|
+
status == 'ignored'
|
157
|
+
rescue Rollbar::Ignore
|
158
|
+
true
|
159
|
+
end
|
160
|
+
|
161
|
+
def report_with_rescue(level, message, exception, extra, context)
|
162
|
+
report(level, message, exception, extra, context)
|
163
|
+
rescue StandardError, SystemStackError => e
|
164
|
+
original_error = {
|
165
|
+
:message => message,
|
166
|
+
:exception => exception,
|
167
|
+
:configuration => configuration
|
168
|
+
}
|
169
|
+
|
170
|
+
report_internal_error(e, original_error)
|
171
|
+
|
172
|
+
'error'
|
173
|
+
end
|
174
|
+
|
175
|
+
# See log() above
|
176
|
+
def debug(*args)
|
177
|
+
log('debug', *args)
|
178
|
+
end
|
179
|
+
|
180
|
+
# See log() above
|
181
|
+
def info(*args)
|
182
|
+
log('info', *args)
|
183
|
+
end
|
184
|
+
|
185
|
+
# See log() above
|
186
|
+
def warn(*args)
|
187
|
+
log('warning', *args)
|
188
|
+
end
|
189
|
+
|
190
|
+
# See log() above
|
191
|
+
def warning(*args)
|
192
|
+
log('warning', *args)
|
193
|
+
end
|
194
|
+
|
195
|
+
# See log() above
|
196
|
+
def error(*args)
|
197
|
+
log('error', *args)
|
198
|
+
end
|
199
|
+
|
200
|
+
# See log() above
|
201
|
+
def critical(*args)
|
202
|
+
log('critical', *args)
|
203
|
+
end
|
204
|
+
|
205
|
+
def enabled?
|
206
|
+
# Require access_token so we don't try to send events when unconfigured.
|
207
|
+
configuration.enabled &&
|
208
|
+
configuration.access_token &&
|
209
|
+
!configuration.access_token.empty?
|
210
|
+
end
|
211
|
+
|
212
|
+
def process_item(item)
|
213
|
+
return send_item(item) unless configuration.write_to_file
|
214
|
+
|
215
|
+
return do_write_item(item) unless configuration.use_async
|
216
|
+
|
217
|
+
MUTEX.synchronize { do_write_item(item) }
|
218
|
+
rescue StandardError => e
|
219
|
+
log_error '[Rollbar] Error processing the item: ' \
|
220
|
+
"#{e.class}, #{e.message}. Item: #{item.payload.inspect}"
|
221
|
+
raise e unless via_failsafe?(item)
|
222
|
+
|
223
|
+
log_error('[Rollbar] Item has already failed. Not re-raising')
|
224
|
+
end
|
225
|
+
|
226
|
+
# We will reraise exceptions in this method so async queues
|
227
|
+
# can retry the job or, in general, handle an error report some way.
|
228
|
+
#
|
229
|
+
# At same time that exception is silenced so we don't generate
|
230
|
+
# infinite reports. This example is what we want to avoid:
|
231
|
+
#
|
232
|
+
# 1. New exception in a the project is raised
|
233
|
+
# 2. That report enqueued to Sidekiq queue.
|
234
|
+
# 3. The Sidekiq job tries to send the report to our API
|
235
|
+
# 4. The report fails, for example cause a network failure,
|
236
|
+
# and a exception is raised
|
237
|
+
# 5. We report an internal error for that exception
|
238
|
+
# 6. We reraise the exception so Sidekiq job fails and
|
239
|
+
# Sidekiq can retry the job reporting the original exception
|
240
|
+
# 7. Because the job failed and Sidekiq can be managed by rollbar we'll
|
241
|
+
# report a new exception.
|
242
|
+
# 8. Go to point 2.
|
243
|
+
#
|
244
|
+
# We'll then push to Sidekiq queue indefinitely until the network failure
|
245
|
+
# is fixed.
|
246
|
+
#
|
247
|
+
# Using Rollbar.silenced we avoid the above behavior but Sidekiq
|
248
|
+
# will have a chance to retry the original job.
|
249
|
+
def process_from_async_handler(payload)
|
250
|
+
Rollbar.silenced do
|
251
|
+
begin
|
252
|
+
if payload.is_a?(String)
|
253
|
+
# The final payload has already been built.
|
254
|
+
send_body(payload)
|
255
|
+
else
|
256
|
+
item = build_item_with_payload(payload)
|
257
|
+
|
258
|
+
process_item(item)
|
259
|
+
end
|
260
|
+
rescue StandardError => e
|
261
|
+
report_internal_error(e)
|
262
|
+
|
263
|
+
raise
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def build_item_with_payload(payload)
|
269
|
+
Item.build_with(payload, :notifier => self,
|
270
|
+
:configuration => configuration,
|
271
|
+
:logger => logger)
|
272
|
+
end
|
273
|
+
|
274
|
+
def failsafe_initial_data(exception_reason)
|
275
|
+
{
|
276
|
+
:level => 'error',
|
277
|
+
:environment => configuration.environment.to_s,
|
278
|
+
:body => {
|
279
|
+
:message => {
|
280
|
+
:body => failsafe_body(exception_reason)
|
281
|
+
}
|
282
|
+
},
|
283
|
+
:notifier => {
|
284
|
+
:name => 'rollbar-gem',
|
285
|
+
:version => VERSION
|
286
|
+
},
|
287
|
+
:internal => true,
|
288
|
+
'failsafe' => true
|
289
|
+
}
|
290
|
+
end
|
291
|
+
|
292
|
+
def send_failsafe(message, exception, original_error = nil)
|
293
|
+
exception_reason = failsafe_reason(message, exception)
|
294
|
+
|
295
|
+
log_error "[Rollbar] Sending failsafe response due to #{exception_reason}"
|
296
|
+
|
297
|
+
failsafe_data = failsafe_initial_data(exception_reason)
|
298
|
+
|
299
|
+
failsafe_add_original_error_data(failsafe_data[:notifier], original_error)
|
300
|
+
|
301
|
+
failsafe_payload = {
|
302
|
+
'data' => failsafe_data
|
303
|
+
}
|
304
|
+
|
305
|
+
process_failsafe_item(failsafe_payload)
|
306
|
+
|
307
|
+
failsafe_payload
|
308
|
+
end
|
309
|
+
|
310
|
+
def process_failsafe_item(failsafe_payload)
|
311
|
+
item = build_item_with_payload(failsafe_payload)
|
312
|
+
process_item(item)
|
313
|
+
log_and_return_item_data(item)
|
314
|
+
rescue StandardError => e
|
315
|
+
log_error "[Rollbar] Error sending failsafe : #{e}"
|
316
|
+
end
|
317
|
+
|
318
|
+
def failsafe_add_original_error_data(payload_notifier, original_error)
|
319
|
+
return unless original_error
|
320
|
+
|
321
|
+
payload_notifier[:diagnostic] ||= {}
|
322
|
+
|
323
|
+
add_original_host(payload_notifier[:diagnostic], original_error)
|
324
|
+
add_original_uuid(payload_notifier[:diagnostic], original_error)
|
325
|
+
add_original_message(payload_notifier[:diagnostic], original_error)
|
326
|
+
add_original_error(payload_notifier[:diagnostic], original_error)
|
327
|
+
add_configured_options(payload_notifier, original_error)
|
328
|
+
end
|
329
|
+
|
330
|
+
def add_original_message(diagnostic, original_error)
|
331
|
+
if original_error[:message]
|
332
|
+
diagnostic[:original_message] =
|
333
|
+
original_error[:message].truncate(FAILSAFE_STRING_LENGTH)
|
334
|
+
end
|
335
|
+
rescue StandardError => e
|
336
|
+
diagnostic[:original_message] = "Failed: #{e.message}"
|
337
|
+
end
|
338
|
+
|
339
|
+
def add_original_error(diagnostic, original_error)
|
340
|
+
if original_error[:exception]
|
341
|
+
backtrace = original_error[:exception].backtrace
|
342
|
+
message = original_error[:exception].message
|
343
|
+
diagnostic[:original_error] = {
|
344
|
+
:message => message && message.truncate(FAILSAFE_STRING_LENGTH),
|
345
|
+
:stack => backtrace && backtrace.join(', ').truncate(FAILSAFE_STRING_LENGTH)
|
346
|
+
}
|
347
|
+
end
|
348
|
+
rescue StandardError => e
|
349
|
+
diagnostic[:original_error] = "Failed: #{e.message}"
|
350
|
+
end
|
351
|
+
|
352
|
+
def add_configured_options(payload_notifier, original_error)
|
353
|
+
if original_error[:configuration]
|
354
|
+
configured = original_error[:configuration].configured_options.configured
|
355
|
+
payload_notifier[:configured_options] =
|
356
|
+
::JSON.generate(configured).truncate(FAILSAFE_STRING_LENGTH)
|
357
|
+
end
|
358
|
+
rescue StandardError => e
|
359
|
+
payload_notifier[:configured_options] = "Failed: #{e.message}"
|
360
|
+
end
|
361
|
+
|
362
|
+
def add_original_host(diagnostic, original_error)
|
363
|
+
diagnostic[:original_host] = original_error[:host] if original_error[:host]
|
364
|
+
end
|
365
|
+
|
366
|
+
def add_original_uuid(diagnostic, original_error)
|
367
|
+
diagnostic[:original_uuid] = original_error[:uuid] if original_error[:uuid]
|
368
|
+
end
|
369
|
+
|
370
|
+
## Logging
|
371
|
+
%w[debug info warn error].each do |level|
|
372
|
+
define_method(:"log_#{level}") do |message|
|
373
|
+
logger.send(level, message)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
def logger
|
378
|
+
@logger ||= LoggerProxy.new(configuration.logger)
|
379
|
+
end
|
380
|
+
|
381
|
+
def trace_with_bindings
|
382
|
+
@trace_with_bindings ||= TraceWithBindings.new
|
383
|
+
end
|
384
|
+
|
385
|
+
def exception_bindings
|
386
|
+
trace_with_bindings.exception_frames
|
387
|
+
end
|
388
|
+
|
389
|
+
def current_bindings
|
390
|
+
trace_with_bindings.frames
|
391
|
+
end
|
392
|
+
|
393
|
+
def enable_locals?
|
394
|
+
configuration.locals[:enabled] &&
|
395
|
+
[:app, :all].include?(configuration.send_extra_frame_data)
|
396
|
+
end
|
397
|
+
|
398
|
+
def enable_locals
|
399
|
+
trace_with_bindings.enable if enable_locals?
|
400
|
+
end
|
401
|
+
|
402
|
+
def disable_locals
|
403
|
+
trace_with_bindings.disable if enable_locals?
|
404
|
+
end
|
405
|
+
|
406
|
+
private
|
407
|
+
|
408
|
+
def use_exception_level_filters?(options)
|
409
|
+
option_value = options && options.delete(:use_exception_level_filters)
|
410
|
+
|
411
|
+
return option_value unless option_value.nil?
|
412
|
+
|
413
|
+
configuration.use_exception_level_filters_default
|
414
|
+
end
|
415
|
+
|
416
|
+
def call_before_process(options)
|
417
|
+
options = options_for_handler(options)
|
418
|
+
handlers = configuration.before_process
|
419
|
+
|
420
|
+
handlers.each do |handler|
|
421
|
+
begin
|
422
|
+
status = handler.call(options)
|
423
|
+
return 'ignored' if status == 'ignored'
|
424
|
+
rescue Rollbar::Ignore
|
425
|
+
raise
|
426
|
+
rescue StandardError => e
|
427
|
+
log_error("[Rollbar] Error calling the `before_process` hook: #{e}")
|
428
|
+
|
429
|
+
break
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
def options_for_handler(options)
|
435
|
+
{
|
436
|
+
:level => options[:level],
|
437
|
+
:scope => scope_object,
|
438
|
+
:exception => options[:exception],
|
439
|
+
:message => options[:message],
|
440
|
+
:extra => options[:extra]
|
441
|
+
}
|
442
|
+
end
|
443
|
+
|
444
|
+
def extract_arguments(args)
|
445
|
+
message = exception = extra = context = nil
|
446
|
+
|
447
|
+
args.each do |arg|
|
448
|
+
if arg.is_a?(String)
|
449
|
+
message = arg
|
450
|
+
elsif arg.is_a?(Exception)
|
451
|
+
exception = arg
|
452
|
+
elsif java_exception?(arg)
|
453
|
+
exception = arg
|
454
|
+
elsif arg.is_a?(Hash)
|
455
|
+
extra = arg
|
456
|
+
|
457
|
+
context = extra.delete :custom_data_method_context
|
458
|
+
|
459
|
+
extra = nil if extra.empty?
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
[message, exception, extra, context]
|
464
|
+
end
|
465
|
+
|
466
|
+
def java_exception?(obj)
|
467
|
+
RUBY_PLATFORM == 'java' && obj.is_a?(java.lang.Throwable)
|
468
|
+
end
|
469
|
+
|
470
|
+
def lookup_exception_level(orig_level, exception, use_exception_level_filters)
|
471
|
+
return orig_level unless use_exception_level_filters
|
472
|
+
|
473
|
+
exception_level = filtered_level(exception)
|
474
|
+
return exception_level if exception_level
|
475
|
+
|
476
|
+
orig_level
|
477
|
+
end
|
478
|
+
|
479
|
+
def ignored?(exception, use_exception_level_filters = false)
|
480
|
+
return false unless exception
|
481
|
+
return true if use_exception_level_filters && filtered_level(exception) == 'ignore'
|
482
|
+
return true if exception.instance_variable_get(:@_rollbar_do_not_report)
|
483
|
+
|
484
|
+
false
|
485
|
+
end
|
486
|
+
|
487
|
+
def filtered_level(exception)
|
488
|
+
return unless exception
|
489
|
+
|
490
|
+
filter = configuration.exception_level_filters[exception.class.name]
|
491
|
+
if filter.respond_to?(:call)
|
492
|
+
filter.call(exception)
|
493
|
+
else
|
494
|
+
filter
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
def report(level, message, exception, extra, context)
|
499
|
+
unless message || exception || extra
|
500
|
+
log_error(
|
501
|
+
'[Rollbar] Tried to send a report with no message, exception or extra data.'
|
502
|
+
)
|
503
|
+
|
504
|
+
return 'error'
|
505
|
+
end
|
506
|
+
|
507
|
+
item = build_item(level, message, exception, extra, context)
|
508
|
+
|
509
|
+
return 'ignored' if item.ignored?
|
510
|
+
|
511
|
+
schedule_item(item) if configuration.transmit
|
512
|
+
|
513
|
+
log_and_return_item_data(item)
|
514
|
+
end
|
515
|
+
|
516
|
+
def log_and_return_item_data(item)
|
517
|
+
data = item['data']
|
518
|
+
log_instance_link(data)
|
519
|
+
Rollbar.last_report = data
|
520
|
+
log_data(data) if configuration.log_payload
|
521
|
+
|
522
|
+
data
|
523
|
+
end
|
524
|
+
|
525
|
+
def log_data(data)
|
526
|
+
log_info "[Rollbar] Data: #{data}"
|
527
|
+
end
|
528
|
+
|
529
|
+
# Reports an internal error in the Rollbar library. This will be reported
|
530
|
+
# within the configured Rollbar project. We'll first attempt to provide a
|
531
|
+
# report including the exception traceback. If that fails, we'll fall back
|
532
|
+
# to a more static failsafe response.
|
533
|
+
def report_internal_error(exception, original_error = nil)
|
534
|
+
return if skip_reporting_internal_error(exception)
|
535
|
+
|
536
|
+
failsafe_message = ''
|
537
|
+
log_error(
|
538
|
+
'[Rollbar] Reporting internal error encountered while sending data to Rollbar.'
|
539
|
+
)
|
540
|
+
|
541
|
+
configuration.execute_hook(:on_report_internal_error, exception)
|
542
|
+
|
543
|
+
failsafe_message = 'build_item in exception_data'
|
544
|
+
item = build_item('error', nil, exception, { :internal => true }, nil)
|
545
|
+
|
546
|
+
failsafe_message = 'error in process_item'
|
547
|
+
process_item(item)
|
548
|
+
|
549
|
+
failsafe_message = 'error logging instance link'
|
550
|
+
log_instance_link(item['data'])
|
551
|
+
rescue StandardError => e
|
552
|
+
send_failsafe(failsafe_message, e, original_error)
|
553
|
+
log_error(item ? "[Rollbar] Item: #{item}" : "[Rollbar] Exception: #{exception}")
|
554
|
+
end
|
555
|
+
|
556
|
+
def skip_reporting_internal_error(exception)
|
557
|
+
return true if configuration.ignore_internal_errors == true
|
558
|
+
|
559
|
+
configuration.ignore_internal_errors.each do |error_name|
|
560
|
+
begin
|
561
|
+
error_cls = error_name.split('::').reduce(Module, :const_get)
|
562
|
+
return true if exception.class <= error_cls
|
563
|
+
rescue NameError
|
564
|
+
# Ignore errors and continue matching.
|
565
|
+
# It's possible for a class name in the list to not be resolvable,
|
566
|
+
# and this is ok.
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
false
|
571
|
+
end
|
572
|
+
|
573
|
+
## Payload building functions
|
574
|
+
|
575
|
+
def build_item(level, message, exception, extra, context)
|
576
|
+
options = {
|
577
|
+
:level => level,
|
578
|
+
:message => message,
|
579
|
+
:exception => exception,
|
580
|
+
:extra => extra,
|
581
|
+
:configuration => configuration,
|
582
|
+
:logger => logger,
|
583
|
+
:scope => scope_object,
|
584
|
+
:notifier => self,
|
585
|
+
:context => context
|
586
|
+
}
|
587
|
+
|
588
|
+
item = Item.new(options)
|
589
|
+
item.build
|
590
|
+
|
591
|
+
item
|
592
|
+
end
|
593
|
+
|
594
|
+
## Delivery functions
|
595
|
+
|
596
|
+
def send_using_eventmachine(body)
|
597
|
+
uri = URI.parse(configuration.endpoint)
|
598
|
+
|
599
|
+
headers = { 'X-Rollbar-Access-Token' => configuration.access_token }
|
600
|
+
options = http_proxy_for_em(uri)
|
601
|
+
req = EventMachine::HttpRequest.new(uri.to_s, options).post(:body => body,
|
602
|
+
:head => headers)
|
603
|
+
|
604
|
+
eventmachine_callback(req)
|
605
|
+
eventmachine_errback(req)
|
606
|
+
end
|
607
|
+
|
608
|
+
def eventmachine_callback(req)
|
609
|
+
req.callback do
|
610
|
+
if req.response_header.status == 200
|
611
|
+
log_info '[Rollbar] Success'
|
612
|
+
else
|
613
|
+
log_warning '[Rollbar] Got unexpected status code from Rollbar.io api: ' \
|
614
|
+
"#{req.response_header.status}"
|
615
|
+
log_info "[Rollbar] Response: #{req.response}"
|
616
|
+
end
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
620
|
+
def eventmachine_errback(req)
|
621
|
+
req.errback do
|
622
|
+
log_warning(
|
623
|
+
"[Rollbar] Call to API failed, status code: #{req.response_header.status}"
|
624
|
+
)
|
625
|
+
log_info "[Rollbar] Error's response: #{req.response}"
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
def send_item(item)
|
630
|
+
log_info '[Rollbar] Sending item'
|
631
|
+
|
632
|
+
body = item.dump
|
633
|
+
return unless body
|
634
|
+
|
635
|
+
if configuration.use_eventmachine
|
636
|
+
send_using_eventmachine(body)
|
637
|
+
return
|
638
|
+
end
|
639
|
+
|
640
|
+
send_body(body)
|
641
|
+
end
|
642
|
+
|
643
|
+
def send_body(body)
|
644
|
+
log_info '[Rollbar] Sending json'
|
645
|
+
|
646
|
+
uri = URI.parse(configuration.endpoint)
|
647
|
+
|
648
|
+
handle_response(do_post(uri, body, configuration.access_token))
|
649
|
+
end
|
650
|
+
|
651
|
+
def do_post(uri, body, access_token)
|
652
|
+
http = init_http(uri)
|
653
|
+
|
654
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
655
|
+
|
656
|
+
request.body = pack_ruby260_bytes(body)
|
657
|
+
|
658
|
+
# Ensure the payload token will be used if the option is set.
|
659
|
+
unless configuration.use_payload_access_token
|
660
|
+
request.add_field('X-Rollbar-Access-Token', access_token)
|
661
|
+
end
|
662
|
+
|
663
|
+
handle_net_retries { http.request(request) }
|
664
|
+
end
|
665
|
+
|
666
|
+
def init_http(uri)
|
667
|
+
proxy = http_proxy(uri)
|
668
|
+
http = Net::HTTP.new(uri.host, uri.port, proxy.host, proxy.port, proxy.user,
|
669
|
+
proxy.password)
|
670
|
+
|
671
|
+
init_http_timeouts(http)
|
672
|
+
|
673
|
+
if uri.scheme == 'https'
|
674
|
+
http.use_ssl = true
|
675
|
+
http.verify_mode = ssl_verify_mode
|
676
|
+
end
|
677
|
+
|
678
|
+
http
|
679
|
+
end
|
680
|
+
|
681
|
+
def init_http_timeouts(http)
|
682
|
+
http.open_timeout = configuration.open_timeout
|
683
|
+
http.read_timeout = configuration.request_timeout
|
684
|
+
end
|
685
|
+
|
686
|
+
def pack_ruby260_bytes(body)
|
687
|
+
# Ruby 2.6.0 shipped with a bug affecting multi-byte body for Net::HTTP.
|
688
|
+
# Fix (committed one day after 2.6.0p0 shipped) is here:
|
689
|
+
# ruby/ruby/commit/1680a13a926b17661329beec1ded6b32aad16c1b
|
690
|
+
#
|
691
|
+
# We work around this by repacking the body as single byte chars if needed.
|
692
|
+
if RUBY_VERSION == '2.6.0' && multibyte?(body)
|
693
|
+
body.unpack('C*').pack('C*')
|
694
|
+
else
|
695
|
+
body
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
def multibyte?(str)
|
700
|
+
str.chars.length != str.bytes.length
|
701
|
+
end
|
702
|
+
|
703
|
+
def http_proxy_for_em(uri)
|
704
|
+
proxy = http_proxy(uri)
|
705
|
+
{
|
706
|
+
:proxy => {
|
707
|
+
:host => proxy.host,
|
708
|
+
:port => proxy.port,
|
709
|
+
:authorization => [proxy.user, proxy.password]
|
710
|
+
}
|
711
|
+
}
|
712
|
+
end
|
713
|
+
|
714
|
+
def http_proxy(uri)
|
715
|
+
@http_proxy ||= proxy_from_config || proxy_from_env(uri) || null_proxy
|
716
|
+
end
|
717
|
+
|
718
|
+
def proxy_from_config
|
719
|
+
proxy_settings = configuration.proxy
|
720
|
+
return nil unless proxy_settings
|
721
|
+
|
722
|
+
proxy = null_proxy
|
723
|
+
proxy.host = URI.parse(proxy_settings[:host]).host
|
724
|
+
proxy.port = proxy_settings[:port]
|
725
|
+
proxy.user = proxy_settings[:user]
|
726
|
+
proxy.password = proxy_settings[:password]
|
727
|
+
proxy
|
728
|
+
end
|
729
|
+
|
730
|
+
def proxy_from_env(uri)
|
731
|
+
uri.find_proxy
|
732
|
+
end
|
733
|
+
|
734
|
+
def null_proxy
|
735
|
+
Struct.new(:host, :port, :user, :password).new
|
736
|
+
end
|
737
|
+
|
738
|
+
def handle_net_retries
|
739
|
+
retries = configuration.net_retries - 1
|
740
|
+
|
741
|
+
begin
|
742
|
+
yield
|
743
|
+
rescue *LanguageSupport.timeout_exceptions
|
744
|
+
raise if retries <= 0
|
745
|
+
|
746
|
+
retries -= 1
|
747
|
+
|
748
|
+
retry
|
749
|
+
end
|
750
|
+
end
|
751
|
+
|
752
|
+
def handle_response(response)
|
753
|
+
if response.code == '200'
|
754
|
+
log_info '[Rollbar] Success'
|
755
|
+
else
|
756
|
+
log_warning(
|
757
|
+
"[Rollbar] Got unexpected status code from Rollbar api: #{response.code}"
|
758
|
+
)
|
759
|
+
log_info "[Rollbar] Response: #{response.body}"
|
760
|
+
configuration.execute_hook(:on_error_response, response)
|
761
|
+
end
|
762
|
+
end
|
763
|
+
|
764
|
+
def ssl_verify_mode
|
765
|
+
if configuration.verify_ssl_peer
|
766
|
+
OpenSSL::SSL::VERIFY_PEER
|
767
|
+
else
|
768
|
+
OpenSSL::SSL::VERIFY_NONE
|
769
|
+
end
|
770
|
+
end
|
771
|
+
|
772
|
+
def do_write_item(item)
|
773
|
+
log_info '[Rollbar] Writing item to file'
|
774
|
+
|
775
|
+
body = item.dump
|
776
|
+
return unless body
|
777
|
+
|
778
|
+
file_name = file_name_with_pid(configuration)
|
779
|
+
|
780
|
+
begin
|
781
|
+
@file ||= File.open(file_name, 'a')
|
782
|
+
|
783
|
+
@file.puts(body)
|
784
|
+
@file.flush
|
785
|
+
update_file(@file, file_name)
|
786
|
+
|
787
|
+
log_info '[Rollbar] Success'
|
788
|
+
rescue IOError => e
|
789
|
+
log_error "[Rollbar] Error opening/writing to file: #{e}"
|
790
|
+
end
|
791
|
+
end
|
792
|
+
|
793
|
+
def file_name_with_pid(configuration)
|
794
|
+
if configuration.files_with_pid_name_enabled
|
795
|
+
configuration.filepath.gsub(EXTENSION_REGEXP, "_#{Process.pid}\\0")
|
796
|
+
else
|
797
|
+
configuration.filepath
|
798
|
+
end
|
799
|
+
end
|
800
|
+
|
801
|
+
def update_file(file, file_name)
|
802
|
+
return unless configuration.files_processed_enabled
|
803
|
+
|
804
|
+
time_now = Time.now
|
805
|
+
if configuration.files_processed_duration > time_now - file.birthtime &&
|
806
|
+
file.size < configuration.files_processed_size
|
807
|
+
return
|
808
|
+
end
|
809
|
+
|
810
|
+
new_file_name = file_name.gsub(EXTENSION_REGEXP, "_processed_#{time_now.to_i}\\0")
|
811
|
+
File.rename(file, new_file_name)
|
812
|
+
file.close
|
813
|
+
@file = File.open(file_name, 'a')
|
814
|
+
end
|
815
|
+
|
816
|
+
def failsafe_reason(message, exception)
|
817
|
+
return failsafe_exception_reason(message, exception) if exception
|
818
|
+
|
819
|
+
message.to_s
|
820
|
+
rescue StandardError
|
821
|
+
log_error('[Rollbar] Error building failsafe message')
|
822
|
+
''
|
823
|
+
end
|
824
|
+
|
825
|
+
def failsafe_exception_reason(message, exception)
|
826
|
+
backtrace = exception.backtrace || []
|
827
|
+
nearest_frame = backtrace[0]
|
828
|
+
|
829
|
+
exception_info = exception.class.name
|
830
|
+
# #to_s and #message defaults to class.to_s.
|
831
|
+
# Add message only if add valuable info.
|
832
|
+
if exception.message != exception.class.to_s
|
833
|
+
exception_info += %[: "#{exception.message}"]
|
834
|
+
end
|
835
|
+
exception_info += " in #{nearest_frame}" if nearest_frame
|
836
|
+
|
837
|
+
"#{exception_info}: #{message}"
|
838
|
+
rescue StandardError
|
839
|
+
log_error('[Rollbar] Error building failsafe exception message')
|
840
|
+
''
|
841
|
+
end
|
842
|
+
|
843
|
+
def failsafe_body(reason)
|
844
|
+
"Failsafe from rollbar-gem. #{reason}"
|
845
|
+
end
|
846
|
+
|
847
|
+
def schedule_item(item)
|
848
|
+
return unless item
|
849
|
+
|
850
|
+
log_info '[Rollbar] Scheduling item'
|
851
|
+
|
852
|
+
if configuration.use_async
|
853
|
+
process_async_item(item)
|
854
|
+
else
|
855
|
+
process_item(item)
|
856
|
+
end
|
857
|
+
end
|
858
|
+
|
859
|
+
def default_async_handler
|
860
|
+
return Rollbar::Delay::GirlFriday if defined?(GirlFriday)
|
861
|
+
|
862
|
+
Rollbar::Delay::Thread
|
863
|
+
end
|
864
|
+
|
865
|
+
def process_async_item(item)
|
866
|
+
# Send async payloads as JSON string when async_json_payload is set.
|
867
|
+
payload = configuration.async_json_payload ? item.dump : item.payload
|
868
|
+
|
869
|
+
configuration.async_handler ||= default_async_handler
|
870
|
+
configuration.async_handler.call(payload)
|
871
|
+
rescue StandardError
|
872
|
+
if configuration.failover_handlers.empty?
|
873
|
+
log_error '[Rollbar] Async handler failed, and there are no failover ' \
|
874
|
+
'handlers configured. See the docs for "failover_handlers"'
|
875
|
+
return
|
876
|
+
end
|
877
|
+
|
878
|
+
async_failover(item)
|
879
|
+
end
|
880
|
+
|
881
|
+
def async_failover(item)
|
882
|
+
log_warning '[Rollbar] Primary async handler failed. Trying failovers...'
|
883
|
+
|
884
|
+
failover_handlers = configuration.failover_handlers
|
885
|
+
|
886
|
+
failover_handlers.each do |handler|
|
887
|
+
begin
|
888
|
+
handler.call(item.payload)
|
889
|
+
rescue StandardError
|
890
|
+
next unless handler == failover_handlers.last
|
891
|
+
|
892
|
+
log_error '[Rollbar] All failover handlers failed while processing ' \
|
893
|
+
"item: #{Rollbar::JSON.dump(item.payload)}"
|
894
|
+
end
|
895
|
+
end
|
896
|
+
end
|
897
|
+
|
898
|
+
alias log_warning log_warn
|
899
|
+
|
900
|
+
def log_instance_link(data)
|
901
|
+
return unless data[:uuid]
|
902
|
+
|
903
|
+
uuid_url = Util.uuid_rollbar_url(data, configuration)
|
904
|
+
log_info(
|
905
|
+
"[Rollbar] Details: #{uuid_url} (only available if report was successful)"
|
906
|
+
)
|
907
|
+
end
|
908
|
+
|
909
|
+
def via_failsafe?(item)
|
910
|
+
item.payload.fetch('data', {}).fetch('failsafe', false)
|
911
|
+
end
|
912
|
+
end
|
913
|
+
end
|