rollbar 2.7.1 → 2.8.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 +4 -4
- data/.gitignore +4 -0
- data/.gitmodules +3 -0
- data/.rubocop.yml +21 -0
- data/.travis.yml +1 -4
- data/CHANGELOG.md +25 -0
- data/README.md +146 -4
- data/Rakefile +5 -3
- data/data/rollbar.snippet.js +1 -0
- data/docs/configuration_options.md +281 -0
- data/lib/rollbar.rb +122 -32
- data/lib/rollbar/configuration.rb +18 -0
- data/lib/rollbar/exceptions.rb +3 -0
- data/lib/rollbar/js.rb +32 -0
- data/lib/rollbar/js/frameworks.rb +6 -0
- data/lib/rollbar/js/frameworks/rails.rb +29 -0
- data/lib/rollbar/js/middleware.rb +129 -0
- data/lib/rollbar/js/version.rb +5 -0
- data/lib/rollbar/lazy_store.rb +83 -0
- data/lib/rollbar/tasks/rollbar.cap +1 -1
- data/lib/rollbar/version.rb +1 -1
- data/lib/tasks/tasks.rake +13 -0
- data/rollbar.gemspec +1 -1
- data/spec/dummyapp/app/controllers/home_controller.rb +4 -0
- data/spec/dummyapp/app/views/js/test.html.erb +1 -0
- data/spec/dummyapp/app/views/layouts/simple.html.erb +18 -0
- data/spec/dummyapp/config/initializers/rollbar.rb +5 -2
- data/spec/dummyapp/config/routes.rb +1 -0
- data/spec/rollbar/js/frameworks/rails_spec.rb +19 -0
- data/spec/rollbar/js/middleware_spec.rb +154 -0
- data/spec/rollbar/lazy_store_spec.rb +99 -0
- data/spec/rollbar_spec.rb +272 -11
- data/spec/spec_helper.rb +2 -8
- metadata +26 -4
data/lib/rollbar.rb
CHANGED
@@ -11,6 +11,7 @@ end
|
|
11
11
|
|
12
12
|
require 'rollbar/version'
|
13
13
|
require 'rollbar/json'
|
14
|
+
require 'rollbar/js'
|
14
15
|
require 'rollbar/configuration'
|
15
16
|
require 'rollbar/encoding'
|
16
17
|
require 'rollbar/logger_proxy'
|
@@ -20,6 +21,8 @@ require 'rollbar/railtie' if defined?(Rails::VERSION)
|
|
20
21
|
require 'rollbar/delay/girl_friday' if defined?(GirlFriday)
|
21
22
|
require 'rollbar/delay/thread'
|
22
23
|
require 'rollbar/truncation'
|
24
|
+
require 'rollbar/exceptions'
|
25
|
+
require 'rollbar/lazy_store'
|
23
26
|
|
24
27
|
module Rollbar
|
25
28
|
ATTACHMENT_CLASSES = %w[
|
@@ -33,18 +36,20 @@ module Rollbar
|
|
33
36
|
class Notifier
|
34
37
|
attr_accessor :configuration
|
35
38
|
attr_accessor :last_report
|
39
|
+
attr_reader :scope_object
|
36
40
|
|
37
41
|
@file_semaphore = Mutex.new
|
38
42
|
|
39
|
-
def initialize(parent_notifier = nil, payload_options = nil)
|
43
|
+
def initialize(parent_notifier = nil, payload_options = nil, scope = nil)
|
40
44
|
if parent_notifier
|
41
45
|
@configuration = parent_notifier.configuration.clone
|
46
|
+
@scope_object = parent_notifier.scope_object.clone
|
42
47
|
|
43
|
-
if payload_options
|
44
|
-
|
45
|
-
end
|
48
|
+
Rollbar::Util.deep_merge(@configuration.payload_options, payload_options) if payload_options
|
49
|
+
Rollbar::Util.deep_merge(@scope_object, scope) if scope
|
46
50
|
else
|
47
51
|
@configuration = ::Rollbar::Configuration.new
|
52
|
+
@scope_object = ::Rollbar::LazyStore.new(scope)
|
48
53
|
end
|
49
54
|
end
|
50
55
|
|
@@ -62,11 +67,12 @@ module Rollbar
|
|
62
67
|
end
|
63
68
|
|
64
69
|
def scope(options = {})
|
65
|
-
self.class.new(self, options)
|
70
|
+
self.class.new(self, nil, options)
|
66
71
|
end
|
67
72
|
|
68
73
|
def scope!(options = {})
|
69
|
-
Rollbar::Util.deep_merge(
|
74
|
+
Rollbar::Util.deep_merge(scope_object, options)
|
75
|
+
|
70
76
|
self
|
71
77
|
end
|
72
78
|
|
@@ -117,33 +123,28 @@ module Rollbar
|
|
117
123
|
def log(level, *args)
|
118
124
|
return 'disabled' unless configuration.enabled
|
119
125
|
|
120
|
-
message =
|
121
|
-
exception = nil
|
122
|
-
extra = nil
|
123
|
-
|
124
|
-
args.each do |arg|
|
125
|
-
if arg.is_a?(String)
|
126
|
-
message = arg
|
127
|
-
elsif arg.is_a?(Exception)
|
128
|
-
exception = arg
|
129
|
-
elsif arg.is_a?(Hash)
|
130
|
-
extra = arg
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
126
|
+
message, exception, extra = extract_arguments(args)
|
134
127
|
use_exception_level_filters = extra && extra.delete(:use_exception_level_filters) == true
|
135
128
|
|
136
129
|
return 'ignored' if ignored?(exception, use_exception_level_filters)
|
137
130
|
|
138
|
-
|
139
|
-
|
140
|
-
|
131
|
+
begin
|
132
|
+
call_before_process(:level => level,
|
133
|
+
:exception => exception,
|
134
|
+
:message => message,
|
135
|
+
:extra => extra)
|
136
|
+
rescue Rollbar::Ignore
|
137
|
+
return 'ignored'
|
141
138
|
end
|
142
139
|
|
140
|
+
level = lookup_exception_level(level, exception,
|
141
|
+
use_exception_level_filters)
|
142
|
+
|
143
143
|
begin
|
144
144
|
report(level, message, exception, extra)
|
145
145
|
rescue Exception => e
|
146
146
|
report_internal_error(e)
|
147
|
+
|
147
148
|
'error'
|
148
149
|
end
|
149
150
|
end
|
@@ -241,6 +242,56 @@ module Rollbar
|
|
241
242
|
|
242
243
|
private
|
243
244
|
|
245
|
+
def call_before_process(options)
|
246
|
+
options = {
|
247
|
+
:level => options[:level],
|
248
|
+
:scope => scope_object,
|
249
|
+
:exception => options[:exception],
|
250
|
+
:message => options[:message],
|
251
|
+
:extra => options[:extra]
|
252
|
+
}
|
253
|
+
handlers = configuration.before_process
|
254
|
+
|
255
|
+
handlers.each do |handler|
|
256
|
+
begin
|
257
|
+
handler.call(options)
|
258
|
+
rescue Rollbar::Ignore
|
259
|
+
raise
|
260
|
+
rescue => e
|
261
|
+
log_error("[Rollbar] Error calling the `before_process` hook: #{e}")
|
262
|
+
|
263
|
+
break
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def extract_arguments(args)
|
269
|
+
message = nil
|
270
|
+
exception = nil
|
271
|
+
extra = nil
|
272
|
+
|
273
|
+
args.each do |arg|
|
274
|
+
if arg.is_a?(String)
|
275
|
+
message = arg
|
276
|
+
elsif arg.is_a?(Exception)
|
277
|
+
exception = arg
|
278
|
+
elsif arg.is_a?(Hash)
|
279
|
+
extra = arg
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
[message, exception, extra]
|
284
|
+
end
|
285
|
+
|
286
|
+
def lookup_exception_level(orig_level, exception, use_exception_level_filters)
|
287
|
+
return orig_level unless use_exception_level_filters
|
288
|
+
|
289
|
+
exception_level = filtered_level(exception)
|
290
|
+
return exception_level if exception_level
|
291
|
+
|
292
|
+
orig_level
|
293
|
+
end
|
294
|
+
|
244
295
|
def ignored?(exception, use_exception_level_filters = false)
|
245
296
|
return false unless exception
|
246
297
|
return true if use_exception_level_filters && filtered_level(exception) == 'ignore'
|
@@ -336,10 +387,7 @@ module Rollbar
|
|
336
387
|
data[:uuid] = SecureRandom.uuid if defined?(SecureRandom) && SecureRandom.respond_to?(:uuid)
|
337
388
|
|
338
389
|
Rollbar::Util.deep_merge(data, configuration.payload_options)
|
339
|
-
|
340
|
-
data[:person] = data[:person].call if data[:person].respond_to?(:call)
|
341
|
-
data[:request] = data[:request].call if data[:request].respond_to?(:call)
|
342
|
-
data[:context] = data[:context].call if data[:context].respond_to?(:call)
|
390
|
+
Rollbar::Util.deep_merge(data, scope_object)
|
343
391
|
|
344
392
|
# Our API doesn't allow null context values, so just delete
|
345
393
|
# the key if value is nil.
|
@@ -352,9 +400,37 @@ module Rollbar
|
|
352
400
|
|
353
401
|
enforce_valid_utf8(payload)
|
354
402
|
|
403
|
+
call_transform(:level => level,
|
404
|
+
:exception => exception,
|
405
|
+
:message => message,
|
406
|
+
:extra => extra,
|
407
|
+
:payload => payload)
|
408
|
+
|
355
409
|
payload
|
356
410
|
end
|
357
411
|
|
412
|
+
def call_transform(options)
|
413
|
+
options = {
|
414
|
+
:level => options[:level],
|
415
|
+
:scope => scope_object,
|
416
|
+
:exception => options[:exception],
|
417
|
+
:message => options[:message],
|
418
|
+
:extra => options[:extra],
|
419
|
+
:payload => options[:payload]
|
420
|
+
}
|
421
|
+
handlers = configuration.transform
|
422
|
+
|
423
|
+
handlers.each do |handler|
|
424
|
+
begin
|
425
|
+
handler.call(options)
|
426
|
+
rescue => e
|
427
|
+
log_error("[Rollbar] Error calling the `transform` hook: #{e}")
|
428
|
+
|
429
|
+
break
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
358
434
|
def build_payload_body(message, exception, extra)
|
359
435
|
extra = Rollbar::Util.deep_merge(custom_data, extra || {}) if custom_data_method?
|
360
436
|
|
@@ -372,7 +448,7 @@ module Rollbar
|
|
372
448
|
def report_custom_data_error(e)
|
373
449
|
data = safely.error(e)
|
374
450
|
|
375
|
-
return {} unless data[:uuid]
|
451
|
+
return {} unless data.is_a?(Hash) && data[:uuid]
|
376
452
|
|
377
453
|
uuid_url = uuid_rollbar_url(data)
|
378
454
|
|
@@ -744,6 +820,8 @@ module Rollbar
|
|
744
820
|
# to configure it without initializing any of the third party hooks
|
745
821
|
def preconfigure
|
746
822
|
yield(configuration)
|
823
|
+
|
824
|
+
reset_notifier!
|
747
825
|
end
|
748
826
|
|
749
827
|
def configure
|
@@ -752,9 +830,7 @@ module Rollbar
|
|
752
830
|
|
753
831
|
yield(configuration)
|
754
832
|
|
755
|
-
|
756
|
-
require_core_extensions
|
757
|
-
|
833
|
+
prepare
|
758
834
|
reset_notifier!
|
759
835
|
end
|
760
836
|
|
@@ -774,10 +850,24 @@ module Rollbar
|
|
774
850
|
@configuration ||= Configuration.new
|
775
851
|
end
|
776
852
|
|
853
|
+
def scope_object
|
854
|
+
@scope_obejct ||= ::Rollbar::LazyStore.new({})
|
855
|
+
end
|
856
|
+
|
777
857
|
def safely?
|
778
858
|
configuration.safely?
|
779
859
|
end
|
780
860
|
|
861
|
+
def prepare
|
862
|
+
prepare_js
|
863
|
+
require_hooks
|
864
|
+
require_core_extensions
|
865
|
+
end
|
866
|
+
|
867
|
+
def prepare_js
|
868
|
+
::Rollbar::Js.prepare if configuration.js_enabled
|
869
|
+
end
|
870
|
+
|
781
871
|
def require_hooks
|
782
872
|
return if configuration.disable_monkey_patch
|
783
873
|
wrap_delayed_worker
|
@@ -786,7 +876,7 @@ module Rollbar
|
|
786
876
|
require 'rollbar/sidekiq' if defined?(Sidekiq)
|
787
877
|
require 'rollbar/active_job' if defined?(ActiveJob)
|
788
878
|
require 'rollbar/goalie' if defined?(Goalie)
|
789
|
-
require 'rollbar/rack' if defined?(Rack)
|
879
|
+
require 'rollbar/rack' if defined?(Rack) unless configuration.disable_rack_monkey_patch
|
790
880
|
require 'rollbar/rake' if defined?(Rake)
|
791
881
|
end
|
792
882
|
|
@@ -6,11 +6,13 @@ module Rollbar
|
|
6
6
|
attr_accessor :access_token
|
7
7
|
attr_accessor :async_handler
|
8
8
|
attr_accessor :branch
|
9
|
+
attr_accessor :before_process
|
9
10
|
attr_accessor :code_version
|
10
11
|
attr_accessor :custom_data_method
|
11
12
|
attr_accessor :delayed_job_enabled
|
12
13
|
attr_accessor :default_logger
|
13
14
|
attr_accessor :disable_monkey_patch
|
15
|
+
attr_accessor :disable_rack_monkey_patch
|
14
16
|
attr_accessor :disable_core_monkey_patch
|
15
17
|
attr_accessor :dj_threshold
|
16
18
|
attr_accessor :enabled
|
@@ -31,6 +33,8 @@ module Rollbar
|
|
31
33
|
attr_accessor :report_dj_data
|
32
34
|
attr_accessor :request_timeout
|
33
35
|
attr_accessor :root
|
36
|
+
attr_accessor :js_options
|
37
|
+
attr_accessor :js_enabled
|
34
38
|
attr_accessor :safely
|
35
39
|
attr_accessor :scrub_fields
|
36
40
|
attr_accessor :scrub_user
|
@@ -40,6 +44,7 @@ module Rollbar
|
|
40
44
|
attr_accessor :uncaught_exception_level
|
41
45
|
attr_accessor :scrub_headers
|
42
46
|
attr_accessor :sidekiq_threshold
|
47
|
+
attr_accessor :transform
|
43
48
|
attr_accessor :verify_ssl_peer
|
44
49
|
attr_accessor :use_async
|
45
50
|
attr_accessor :use_eventmachine
|
@@ -55,12 +60,14 @@ module Rollbar
|
|
55
60
|
|
56
61
|
def initialize
|
57
62
|
@async_handler = nil
|
63
|
+
@before_process = []
|
58
64
|
@code_version = nil
|
59
65
|
@custom_data_method = nil
|
60
66
|
@default_logger = lambda { Logger.new(STDERR) }
|
61
67
|
@delayed_job_enabled = true
|
62
68
|
@disable_monkey_patch = false
|
63
69
|
@disable_core_monkey_patch = false
|
70
|
+
@disable_rack_monkey_patch = false
|
64
71
|
@dj_threshold = 0
|
65
72
|
@enabled = nil # set to true when configure is called
|
66
73
|
@endpoint = DEFAULT_ENDPOINT
|
@@ -82,6 +89,8 @@ module Rollbar
|
|
82
89
|
@populate_empty_backtraces = false
|
83
90
|
@report_dj_data = true
|
84
91
|
@request_timeout = 3
|
92
|
+
@js_enabled = false
|
93
|
+
@js_options = {}
|
85
94
|
@scrub_fields = [:passwd, :password, :password_confirmation, :secret,
|
86
95
|
:confirm_password, :password_confirmation, :secret_token,
|
87
96
|
:api_key, :access_token ]
|
@@ -92,6 +101,7 @@ module Rollbar
|
|
92
101
|
@scrub_headers = ['Authorization']
|
93
102
|
@sidekiq_threshold = 0
|
94
103
|
@safely = false
|
104
|
+
@transform = []
|
95
105
|
@use_async = false
|
96
106
|
@use_eventmachine = false
|
97
107
|
@verify_ssl_peer = true
|
@@ -164,6 +174,14 @@ module Rollbar
|
|
164
174
|
end.flatten.uniq.map(&:gem_dir)
|
165
175
|
end
|
166
176
|
|
177
|
+
def before_process=(*handler)
|
178
|
+
@before_process = Array(handler)
|
179
|
+
end
|
180
|
+
|
181
|
+
def transform=(*handler)
|
182
|
+
@transform = Array(handler)
|
183
|
+
end
|
184
|
+
|
167
185
|
# allow params to be read like a hash
|
168
186
|
def [](option)
|
169
187
|
send(option)
|
data/lib/rollbar/js.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "rollbar/js/version"
|
2
|
+
|
3
|
+
module Rollbar
|
4
|
+
module Js
|
5
|
+
extend self
|
6
|
+
|
7
|
+
attr_reader :framework
|
8
|
+
attr_reader :framework_loader
|
9
|
+
|
10
|
+
def prepare
|
11
|
+
@framework ||= detect_framework
|
12
|
+
@framework_loader ||= load_framework_class.new
|
13
|
+
|
14
|
+
@framework_loader.prepare
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def detect_framework
|
20
|
+
case
|
21
|
+
when defined?(::Rails::VERSION)
|
22
|
+
:rails
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def load_framework_class
|
27
|
+
require "rollbar/js/frameworks/#{framework}"
|
28
|
+
|
29
|
+
Rollbar::Js::Frameworks.const_get(framework.to_s.capitalize)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rollbar
|
2
|
+
module Js
|
3
|
+
module Frameworks
|
4
|
+
class Rails
|
5
|
+
attr_accessor :prepared
|
6
|
+
|
7
|
+
alias prepared? prepared
|
8
|
+
|
9
|
+
def prepare
|
10
|
+
return if prepared?
|
11
|
+
|
12
|
+
require 'rollbar/js/middleware'
|
13
|
+
|
14
|
+
config = {
|
15
|
+
:options => Rollbar.configuration.js_options,
|
16
|
+
:enabled => Rollbar.configuration.js_enabled
|
17
|
+
}
|
18
|
+
rails_config.middleware.use(::Rollbar::Js::Middleware, config)
|
19
|
+
|
20
|
+
self.prepared = true
|
21
|
+
end
|
22
|
+
|
23
|
+
def rails_config
|
24
|
+
::Rails.configuration
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'rack/response'
|
3
|
+
|
4
|
+
|
5
|
+
module Rollbar
|
6
|
+
module Js
|
7
|
+
class Middleware
|
8
|
+
attr_reader :app
|
9
|
+
attr_reader :config
|
10
|
+
|
11
|
+
JS_IS_INJECTED_KEY = 'rollbar.js_is_injected'
|
12
|
+
SNIPPET = File.read(File.expand_path('../../../../data/rollbar.snippet.js', __FILE__))
|
13
|
+
|
14
|
+
def initialize(app, config)
|
15
|
+
@app = app
|
16
|
+
@config = config
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
result = app.call(env)
|
21
|
+
|
22
|
+
_call(env, result)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def _call(env, result)
|
28
|
+
return result unless should_add_js?(env, result[0], result[1])
|
29
|
+
|
30
|
+
if response_string = add_js(result[2])
|
31
|
+
env[JS_IS_INJECTED_KEY] = true
|
32
|
+
response = ::Rack::Response.new(response_string, result[0], result[1])
|
33
|
+
|
34
|
+
response.finish
|
35
|
+
else
|
36
|
+
result
|
37
|
+
end
|
38
|
+
rescue => e
|
39
|
+
Rollbar.log_error("[Rollbar] Rollbar.js could not be added because #{e} exception")
|
40
|
+
result
|
41
|
+
end
|
42
|
+
|
43
|
+
def enabled?
|
44
|
+
!!config[:enabled]
|
45
|
+
end
|
46
|
+
|
47
|
+
def should_add_js?(env, status, headers)
|
48
|
+
enabled? &&
|
49
|
+
status == 200 &&
|
50
|
+
!env[JS_IS_INJECTED_KEY] &&
|
51
|
+
html?(headers) &&
|
52
|
+
!attachment?(headers) &&
|
53
|
+
!streaming?(env)
|
54
|
+
end
|
55
|
+
|
56
|
+
def html?(headers)
|
57
|
+
headers['Content-Type'] && headers['Content-Type'].include?('text/html')
|
58
|
+
end
|
59
|
+
|
60
|
+
def attachment?(headers)
|
61
|
+
headers['Content-Disposition'].to_s.include?('attachment')
|
62
|
+
end
|
63
|
+
|
64
|
+
def streaming?(env)
|
65
|
+
return false unless defined?(ActionController::Live)
|
66
|
+
|
67
|
+
env['action_controller.instance'].class.included_modules.include?(ActionController::Live)
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_js(response)
|
71
|
+
body = join_body(response)
|
72
|
+
close_old_response(response)
|
73
|
+
|
74
|
+
return nil unless body
|
75
|
+
|
76
|
+
head_open_end = find_end_of_head_open(body)
|
77
|
+
return nil unless head_open_end
|
78
|
+
|
79
|
+
if head_open_end
|
80
|
+
body = body[0..head_open_end] <<
|
81
|
+
config_js_tag <<
|
82
|
+
snippet_js_tag <<
|
83
|
+
body[head_open_end..-1]
|
84
|
+
end
|
85
|
+
|
86
|
+
body
|
87
|
+
rescue => e
|
88
|
+
Rollbar.log_error("[Rollbar] Rollbar.js could not be added because #{e} exception")
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
|
92
|
+
def find_end_of_head_open(body)
|
93
|
+
head_open = body.index('<head')
|
94
|
+
body.index('>', head_open) + 1 if head_open
|
95
|
+
end
|
96
|
+
|
97
|
+
def join_body(response)
|
98
|
+
source = nil
|
99
|
+
response.each { |fragment| source ? (source << fragment.to_s) : (source = fragment.to_s)}
|
100
|
+
source
|
101
|
+
end
|
102
|
+
|
103
|
+
def close_old_response(response)
|
104
|
+
response.close if response.respond_to?(:close)
|
105
|
+
end
|
106
|
+
|
107
|
+
def config_js_tag
|
108
|
+
script_tag("var _rollbarConfig = #{config[:options].to_json};")
|
109
|
+
end
|
110
|
+
|
111
|
+
def snippet_js_tag
|
112
|
+
script_tag(js_snippet)
|
113
|
+
end
|
114
|
+
|
115
|
+
def js_snippet
|
116
|
+
SNIPPET
|
117
|
+
end
|
118
|
+
|
119
|
+
def script_tag(content)
|
120
|
+
html_safe_if_needed("\n<script type=\"text/javascript\">#{content}</script>")
|
121
|
+
end
|
122
|
+
|
123
|
+
def html_safe_if_needed(string)
|
124
|
+
string = string.html_safe if string.respond_to?(:html_safe)
|
125
|
+
string
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|