sentry-raven 2.13.0 → 3.0.4

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.craft.yml +15 -0
  3. data/.github/workflows/test.yml +87 -0
  4. data/.github/workflows/zeus_upload.yml +32 -0
  5. data/.gitignore +2 -0
  6. data/.rubocop.yml +44 -9
  7. data/.scripts/bump-version.sh +9 -0
  8. data/{changelog.md → CHANGELOG.md} +38 -1
  9. data/CONTRIUTING.md +26 -0
  10. data/Gemfile +20 -25
  11. data/README.md +24 -14
  12. data/lib/raven/backtrace.rb +7 -5
  13. data/lib/raven/base.rb +5 -2
  14. data/lib/raven/breadcrumbs.rb +1 -1
  15. data/lib/raven/breadcrumbs/activesupport.rb +10 -10
  16. data/lib/raven/breadcrumbs/logger.rb +3 -3
  17. data/lib/raven/cli.rb +9 -20
  18. data/lib/raven/client.rb +9 -4
  19. data/lib/raven/configuration.rb +20 -6
  20. data/lib/raven/core_ext/object/deep_dup.rb +57 -0
  21. data/lib/raven/core_ext/object/duplicable.rb +153 -0
  22. data/lib/raven/event.rb +4 -2
  23. data/lib/raven/instance.rb +6 -3
  24. data/lib/raven/integrations/delayed_job.rb +13 -14
  25. data/lib/raven/integrations/rack-timeout.rb +2 -3
  26. data/lib/raven/integrations/rack.rb +4 -3
  27. data/lib/raven/integrations/rails.rb +1 -0
  28. data/lib/raven/integrations/rails/active_job.rb +5 -4
  29. data/lib/raven/integrations/rails/overrides/debug_exceptions_catcher.rb +2 -2
  30. data/lib/raven/interface.rb +2 -2
  31. data/lib/raven/interfaces/stack_trace.rb +1 -1
  32. data/lib/raven/linecache.rb +5 -2
  33. data/lib/raven/logger.rb +3 -2
  34. data/lib/raven/processor/cookies.rb +16 -6
  35. data/lib/raven/processor/post_data.rb +2 -0
  36. data/lib/raven/processor/removecircularreferences.rb +3 -1
  37. data/lib/raven/processor/sanitizedata.rb +65 -17
  38. data/lib/raven/processor/utf8conversion.rb +2 -0
  39. data/lib/raven/transports.rb +4 -0
  40. data/lib/raven/transports/http.rb +5 -5
  41. data/lib/raven/utils/exception_cause_chain.rb +1 -0
  42. data/lib/raven/utils/real_ip.rb +1 -1
  43. data/lib/raven/version.rb +2 -2
  44. data/sentry-raven.gemspec +2 -2
  45. metadata +11 -11
  46. data/.travis.yml +0 -47
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## Inspired by Rails' and Airbrake's backtrace parsers.
2
4
 
3
5
  module Raven
@@ -5,16 +7,16 @@ module Raven
5
7
  class Backtrace
6
8
  # Handles backtrace parsing line by line
7
9
  class Line
8
- RB_EXTENSION = ".rb".freeze
10
+ RB_EXTENSION = ".rb"
9
11
  # regexp (optional leading X: on windows, or JRuby9000 class-prefix)
10
12
  RUBY_INPUT_FORMAT = /
11
13
  ^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
12
14
  (\d+)
13
15
  (?: :in \s `([^']+)')?$
14
- /x
16
+ /x.freeze
15
17
 
16
18
  # org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
17
- JAVA_INPUT_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$/
19
+ JAVA_INPUT_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$/.freeze
18
20
 
19
21
  # The file portion of the line (such as app/models/user.rb)
20
22
  attr_reader :file
@@ -74,7 +76,7 @@ module Raven
74
76
 
75
77
  def self.in_app_pattern
76
78
  @in_app_pattern ||= begin
77
- project_root = Raven.configuration.project_root && Raven.configuration.project_root.to_s
79
+ project_root = Raven.configuration.project_root&.to_s
78
80
  Regexp.new("^(#{project_root}/)?#{Raven.configuration.app_dirs_pattern || APP_DIRS_PATTERN}")
79
81
  end
80
82
  end
@@ -84,7 +86,7 @@ module Raven
84
86
  attr_writer :file, :number, :method, :module_name
85
87
  end
86
88
 
87
- APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test)/
89
+ APP_DIRS_PATTERN = /(bin|exe|app|config|lib|test)/.freeze
88
90
 
89
91
  # holder for an Array of Backtrace::Line instances
90
92
  attr_reader :lines
@@ -1,4 +1,5 @@
1
1
  require 'raven/version'
2
+ require 'raven/core_ext/object/deep_dup'
2
3
  require 'raven/backtrace'
3
4
  require 'raven/breadcrumbs'
4
5
  require 'raven/processor'
@@ -85,12 +86,13 @@ module Raven
85
86
 
86
87
  def load_integration(integration)
87
88
  require "raven/integrations/#{integration}"
88
- rescue Exception => error
89
- logger.warn "Unable to load raven/integrations/#{integration}: #{error}"
89
+ rescue Exception => e
90
+ logger.warn "Unable to load raven/integrations/#{integration}: #{e}"
90
91
  end
91
92
 
92
93
  def safely_prepend(module_name, opts = {})
93
94
  return if opts[:to].nil? || opts[:from].nil?
95
+
94
96
  if opts[:to].respond_to?(:prepend, true)
95
97
  opts[:to].send(:prepend, opts[:from].const_get(module_name))
96
98
  else
@@ -101,6 +103,7 @@ module Raven
101
103
  def sys_command(command)
102
104
  result = `#{command} 2>&1` rescue nil
103
105
  return if result.nil? || result.empty? || ($CHILD_STATUS && $CHILD_STATUS.exitstatus != 0)
106
+
104
107
  result.strip
105
108
  end
106
109
  end
@@ -64,7 +64,7 @@ module Raven
64
64
  end
65
65
 
66
66
  def empty?
67
- !members.any?
67
+ members.none?
68
68
  end
69
69
 
70
70
  def to_hash
@@ -1,19 +1,19 @@
1
1
  module Raven
2
2
  module ActiveSupportBreadcrumbs
3
3
  class << self
4
- def add(name, started, _finished, _unique_id, data)
5
- Raven.breadcrumbs.record do |crumb|
6
- crumb.data = data
7
- crumb.category = name
8
- crumb.timestamp = started.to_i
9
- end
4
+ def add(name, started, _finished, _unique_id, data)
5
+ Raven.breadcrumbs.record do |crumb|
6
+ crumb.data = data
7
+ crumb.category = name
8
+ crumb.timestamp = started.to_i
10
9
  end
10
+ end
11
11
 
12
- def inject
13
- ActiveSupport::Notifications.subscribe(/.*/) do |name, started, finished, unique_id, data|
14
- add(name, started, finished, unique_id, data)
15
- end
12
+ def inject
13
+ ActiveSupport::Notifications.subscribe(/.*/) do |name, started, finished, unique_id, data|
14
+ add(name, started, finished, unique_id, data)
16
15
  end
16
+ end
17
17
  end
18
18
  end
19
19
  end
@@ -4,13 +4,13 @@ module Raven
4
4
  module BreadcrumbLogger
5
5
  LEVELS = {
6
6
  ::Logger::DEBUG => 'debug',
7
- ::Logger::INFO => 'info',
8
- ::Logger::WARN => 'warn',
7
+ ::Logger::INFO => 'info',
8
+ ::Logger::WARN => 'warn',
9
9
  ::Logger::ERROR => 'error',
10
10
  ::Logger::FATAL => 'fatal'
11
11
  }.freeze
12
12
 
13
- EXC_FORMAT = /^([a-zA-Z0-9]+)\:\s(.*)$/
13
+ EXC_FORMAT = /^([a-zA-Z0-9]+)\:\s(.*)$/.freeze
14
14
 
15
15
  def self.parse_exception(message)
16
16
  lines = message.split(/\n\s*/)
@@ -18,7 +18,7 @@ module Raven
18
18
 
19
19
  # wipe out env settings to ensure we send the event
20
20
  unless config.capture_allowed?
21
- env_name = config.environments.pop || 'production'
21
+ env_name = config.environments.last || 'production'
22
22
  config.current_environment = env_name
23
23
  end
24
24
 
@@ -29,31 +29,20 @@ module Raven
29
29
 
30
30
  begin
31
31
  1 / 0
32
- rescue ZeroDivisionError => exception
33
- evt = instance.capture_exception(exception)
32
+ rescue ZeroDivisionError => e
33
+ evt = instance.capture_exception(e)
34
34
  end
35
35
 
36
- if evt && !(evt.is_a? Thread)
37
- if evt.is_a? Hash
38
- instance.logger.debug "-> event ID: #{evt[:event_id]}"
39
- else
40
- instance.logger.debug "-> event ID: #{evt.id}"
41
- end
42
- elsif evt # async configuration
43
- if evt.value.is_a? Hash
44
- instance.logger.debug "-> event ID: #{evt.value[:event_id]}"
45
- else
46
- instance.logger.debug "-> event ID: #{evt.value.id}"
47
- end
36
+ if evt
37
+ instance.logger.debug "-> event ID: #{evt.id}"
38
+ instance.logger.debug ""
39
+ instance.logger.debug "Done!"
40
+ evt
48
41
  else
49
42
  instance.logger.debug ""
50
43
  instance.logger.debug "An error occurred while attempting to send the event."
51
- exit 1
44
+ false
52
45
  end
53
-
54
- instance.logger.debug ""
55
- instance.logger.debug "Done!"
56
- evt
57
46
  end
58
47
  end
59
48
  end
@@ -1,14 +1,17 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'base64'
3
4
  require 'json'
4
5
  require 'zlib'
5
6
 
7
+ require "raven/transports"
8
+
6
9
  module Raven
7
10
  # Encodes events and sends them to the Sentry server.
8
11
  class Client
9
- PROTOCOL_VERSION = '5'.freeze
10
- USER_AGENT = "raven-ruby/#{Raven::VERSION}".freeze
11
- CONTENT_TYPE = 'application/json'.freeze
12
+ PROTOCOL_VERSION = '5'
13
+ USER_AGENT = "raven-ruby/#{Raven::VERSION}"
14
+ CONTENT_TYPE = 'application/json'
12
15
 
13
16
  attr_accessor :configuration
14
17
 
@@ -120,7 +123,9 @@ module Raven
120
123
  configuration.logger.warn "Not sending event due to previous failure(s)."
121
124
  end
122
125
  configuration.logger.warn("Failed to submit event: #{get_log_message(event)}")
123
- configuration.transport_failure_callback.call(event) if configuration.transport_failure_callback
126
+
127
+ # configuration.transport_failure_callback can be false & nil
128
+ configuration.transport_failure_callback.call(event) if configuration.transport_failure_callback # rubocop:disable Style/SafeNavigation
124
129
  end
125
130
  end
126
131
 
@@ -236,6 +236,7 @@ module Raven
236
236
 
237
237
  def server=(value)
238
238
  return if value.nil?
239
+
239
240
  uri = URI.parse(value)
240
241
  uri_path = uri.path.split('/')
241
242
 
@@ -253,13 +254,14 @@ module Raven
253
254
 
254
255
  # For anyone who wants to read the base server string
255
256
  @server = "#{scheme}://#{host}"
256
- @server << ":#{port}" unless port == { 'http' => 80, 'https' => 443 }[scheme]
257
- @server << path
257
+ @server += ":#{port}" unless port == { 'http' => 80, 'https' => 443 }[scheme]
258
+ @server += path
258
259
  end
259
260
  alias dsn= server=
260
261
 
261
262
  def encoding=(encoding)
262
263
  raise(Error, 'Unsupported encoding') unless %w(gzip json).include? encoding
264
+
263
265
  @encoding = encoding
264
266
  end
265
267
 
@@ -267,6 +269,7 @@ module Raven
267
269
  unless value == false || value.respond_to?(:call)
268
270
  raise(ArgumentError, "async must be callable (or false to disable)")
269
271
  end
272
+
270
273
  @async = value
271
274
  end
272
275
 
@@ -274,6 +277,7 @@ module Raven
274
277
  unless value == false || value.respond_to?(:call)
275
278
  raise(ArgumentError, "transport_failure_callback must be callable (or false to disable)")
276
279
  end
280
+
277
281
  @transport_failure_callback = value
278
282
  end
279
283
 
@@ -281,6 +285,7 @@ module Raven
281
285
  unless value == false || value.respond_to?(:call)
282
286
  raise ArgumentError, "should_capture must be callable (or false to disable)"
283
287
  end
288
+
284
289
  @should_capture = value
285
290
  end
286
291
 
@@ -288,6 +293,7 @@ module Raven
288
293
  unless value == false || value.respond_to?(:call)
289
294
  raise ArgumentError, "before_send must be callable (or false to disable)"
290
295
  end
296
+
291
297
  @before_send = value
292
298
  end
293
299
 
@@ -336,6 +342,10 @@ module Raven
336
342
  end
337
343
  end
338
344
 
345
+ def enabled_in_current_env?
346
+ environments.empty? || environments.include?(current_environment)
347
+ end
348
+
339
349
  private
340
350
 
341
351
  def detect_project_root
@@ -351,8 +361,8 @@ module Raven
351
361
  detect_release_from_git ||
352
362
  detect_release_from_capistrano ||
353
363
  detect_release_from_heroku
354
- rescue => ex
355
- logger.error "Error detecting release: #{ex.message}"
364
+ rescue => e
365
+ logger.error "Error detecting release: #{e.message}"
356
366
  end
357
367
 
358
368
  def excluded_exception?(incoming_exception)
@@ -417,19 +427,22 @@ module Raven
417
427
  end
418
428
 
419
429
  def capture_in_current_environment?
420
- return true unless environments.any? && !environments.include?(current_environment)
430
+ return true if enabled_in_current_env?
431
+
421
432
  @errors << "Not configured to send/capture in environment '#{current_environment}'"
422
433
  false
423
434
  end
424
435
 
425
436
  def capture_allowed_by_callback?(message_or_exc)
426
- return true if !should_capture || message_or_exc.nil? || should_capture.call(*[message_or_exc])
437
+ return true if !should_capture || message_or_exc.nil? || should_capture.call(message_or_exc)
438
+
427
439
  @errors << "should_capture returned false"
428
440
  false
429
441
  end
430
442
 
431
443
  def valid?
432
444
  return true if %w(server host path public_key project_id).all? { |k| public_send(k) }
445
+
433
446
  if server
434
447
  %w(server host path public_key project_id).map do |key|
435
448
  @errors << "No #{key} specified" unless public_send(key)
@@ -442,6 +455,7 @@ module Raven
442
455
 
443
456
  def sample_allowed?
444
457
  return true if sample_rate == 1.0
458
+
445
459
  if Random::DEFAULT.rand >= sample_rate
446
460
  @errors << "Excluded by random sample"
447
461
  false
@@ -0,0 +1,57 @@
1
+ require 'raven/core_ext/object/duplicable'
2
+
3
+ #########################################
4
+ # This file was copied from Rails 5.2 #
5
+ #########################################
6
+
7
+ class Object
8
+ # Returns a deep copy of object if it's duplicable. If it's
9
+ # not duplicable, returns +self+.
10
+ #
11
+ # object = Object.new
12
+ # dup = object.deep_dup
13
+ # dup.instance_variable_set(:@a, 1)
14
+ #
15
+ # object.instance_variable_defined?(:@a) # => false
16
+ # dup.instance_variable_defined?(:@a) # => true
17
+ def deep_dup
18
+ duplicable? ? dup : self
19
+ end
20
+ end
21
+
22
+ class Array
23
+ # Returns a deep copy of array.
24
+ #
25
+ # array = [1, [2, 3]]
26
+ # dup = array.deep_dup
27
+ # dup[1][2] = 4
28
+ #
29
+ # array[1][2] # => nil
30
+ # dup[1][2] # => 4
31
+ def deep_dup
32
+ map(&:deep_dup)
33
+ end
34
+ end
35
+
36
+ class Hash
37
+ # Returns a deep copy of hash.
38
+ #
39
+ # hash = { a: { b: 'b' } }
40
+ # dup = hash.deep_dup
41
+ # dup[:a][:c] = 'c'
42
+ #
43
+ # hash[:a][:c] # => nil
44
+ # dup[:a][:c] # => "c"
45
+ def deep_dup
46
+ hash = dup
47
+ each_pair do |key, value|
48
+ if key.frozen? && ::String === key
49
+ hash[key] = value.deep_dup
50
+ else
51
+ hash.delete(key)
52
+ hash[key.deep_dup] = value.deep_dup
53
+ end
54
+ end
55
+ hash
56
+ end
57
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ #########################################
4
+ # This file was copied from Rails 5.2 #
5
+ #########################################
6
+
7
+ #--
8
+ # Most objects are cloneable, but not all. For example you can't dup methods:
9
+ #
10
+ # method(:puts).dup # => TypeError: allocator undefined for Method
11
+ #
12
+ # Classes may signal their instances are not duplicable removing +dup+/+clone+
13
+ # or raising exceptions from them. So, to dup an arbitrary object you normally
14
+ # use an optimistic approach and are ready to catch an exception, say:
15
+ #
16
+ # arbitrary_object.dup rescue object
17
+ #
18
+ # Rails dups objects in a few critical spots where they are not that arbitrary.
19
+ # That rescue is very expensive (like 40 times slower than a predicate), and it
20
+ # is often triggered.
21
+ #
22
+ # That's why we hardcode the following cases and check duplicable? instead of
23
+ # using that rescue idiom.
24
+ #++
25
+ class Object
26
+ # Can you safely dup this object?
27
+ #
28
+ # False for method objects;
29
+ # true otherwise.
30
+ def duplicable?
31
+ true
32
+ end
33
+ end
34
+
35
+ class NilClass
36
+ begin
37
+ nil.dup
38
+ rescue TypeError
39
+ # +nil+ is not duplicable:
40
+ #
41
+ # nil.duplicable? # => false
42
+ # nil.dup # => TypeError: can't dup NilClass
43
+ def duplicable?
44
+ false
45
+ end
46
+ end
47
+ end
48
+
49
+ class FalseClass
50
+ begin
51
+ false.dup
52
+ rescue TypeError
53
+ # +false+ is not duplicable:
54
+ #
55
+ # false.duplicable? # => false
56
+ # false.dup # => TypeError: can't dup FalseClass
57
+ def duplicable?
58
+ false
59
+ end
60
+ end
61
+ end
62
+
63
+ class TrueClass
64
+ begin
65
+ true.dup
66
+ rescue TypeError
67
+ # +true+ is not duplicable:
68
+ #
69
+ # true.duplicable? # => false
70
+ # true.dup # => TypeError: can't dup TrueClass
71
+ def duplicable?
72
+ false
73
+ end
74
+ end
75
+ end
76
+
77
+ class Symbol
78
+ begin
79
+ :symbol.dup # Ruby 2.4.x.
80
+ "symbol_from_string".to_sym.dup # Some symbols can't `dup` in Ruby 2.4.0.
81
+ rescue TypeError
82
+ # Symbols are not duplicable:
83
+ #
84
+ # :my_symbol.duplicable? # => false
85
+ # :my_symbol.dup # => TypeError: can't dup Symbol
86
+ def duplicable?
87
+ false
88
+ end
89
+ end
90
+ end
91
+
92
+ class Numeric
93
+ begin
94
+ 1.dup
95
+ rescue TypeError
96
+ # Numbers are not duplicable:
97
+ #
98
+ # 3.duplicable? # => false
99
+ # 3.dup # => TypeError: can't dup Integer
100
+ def duplicable?
101
+ false
102
+ end
103
+ end
104
+ end
105
+
106
+ require "bigdecimal"
107
+ class BigDecimal
108
+ # BigDecimals are duplicable:
109
+ #
110
+ # BigDecimal("1.2").duplicable? # => true
111
+ # BigDecimal("1.2").dup # => #<BigDecimal:...,'0.12E1',18(18)>
112
+ def duplicable?
113
+ true
114
+ end
115
+ end
116
+
117
+ class Method
118
+ # Methods are not duplicable:
119
+ #
120
+ # method(:puts).duplicable? # => false
121
+ # method(:puts).dup # => TypeError: allocator undefined for Method
122
+ def duplicable?
123
+ false
124
+ end
125
+ end
126
+
127
+ class Complex
128
+ begin
129
+ Complex(1).dup
130
+ rescue TypeError
131
+ # Complexes are not duplicable:
132
+ #
133
+ # Complex(1).duplicable? # => false
134
+ # Complex(1).dup # => TypeError: can't copy Complex
135
+ def duplicable?
136
+ false
137
+ end
138
+ end
139
+ end
140
+
141
+ class Rational
142
+ begin
143
+ Rational(1).dup
144
+ rescue TypeError
145
+ # Rationals are not duplicable:
146
+ #
147
+ # Rational(1).duplicable? # => false
148
+ # Rational(1).dup # => TypeError: can't copy Rational
149
+ def duplicable?
150
+ false
151
+ end
152
+ end
153
+ end