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.
@@ -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
- Rollbar::Util.deep_merge(@configuration.payload_options, payload_options)
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(@configuration.payload_options, options)
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 = nil
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
- if use_exception_level_filters
139
- exception_level = filtered_level(exception)
140
- level = exception_level if exception_level
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
- require_hooks
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)
@@ -0,0 +1,3 @@
1
+ module Rollbar
2
+ class Ignore < StandardError; end
3
+ end
@@ -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,6 @@
1
+ module Rollbar
2
+ module Js
3
+ module Frameworks
4
+ end
5
+ end
6
+ 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