sentry-raven 2.9.0 → 3.0.1
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/.craft.yml +14 -0
- data/.github/workflows/test.yml +77 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +44 -9
- data/.scripts/bump-version.sh +9 -0
- data/Gemfile +17 -25
- data/README.md +5 -4
- data/changelog.md +77 -1
- data/lib/raven/backtrace.rb +7 -5
- data/lib/raven/base.rb +5 -3
- data/lib/raven/breadcrumbs/activesupport.rb +10 -10
- data/lib/raven/breadcrumbs/logger.rb +4 -4
- data/lib/raven/breadcrumbs.rb +1 -1
- data/lib/raven/cli.rb +2 -2
- data/lib/raven/client.rb +28 -10
- data/lib/raven/configuration.rb +23 -8
- data/lib/raven/event.rb +5 -9
- data/lib/raven/instance.rb +12 -3
- data/lib/raven/integrations/delayed_job.rb +14 -15
- data/lib/raven/integrations/rack-timeout.rb +2 -3
- data/lib/raven/integrations/rack.rb +4 -3
- data/lib/raven/integrations/rails/active_job.rb +10 -7
- data/lib/raven/integrations/rails/controller_transaction.rb +1 -1
- data/lib/raven/integrations/rails/overrides/debug_exceptions_catcher.rb +2 -2
- data/lib/raven/integrations/rails.rb +1 -0
- data/lib/raven/interface.rb +2 -2
- data/lib/raven/interfaces/stack_trace.rb +1 -1
- data/lib/raven/linecache.rb +5 -2
- data/lib/raven/logger.rb +3 -2
- data/lib/raven/processor/cookies.rb +16 -6
- data/lib/raven/processor/post_data.rb +2 -0
- data/lib/raven/processor/removecircularreferences.rb +1 -0
- data/lib/raven/processor/sanitizedata.rb +65 -17
- data/lib/raven/processor/utf8conversion.rb +3 -1
- data/lib/raven/transports/http.rb +5 -5
- data/lib/raven/transports.rb +4 -0
- data/lib/raven/utils/exception_cause_chain.rb +1 -0
- data/lib/raven/utils/real_ip.rb +1 -1
- data/lib/raven/version.rb +2 -2
- data/sentry-raven.gemspec +3 -3
- metadata +8 -13
- data/.travis.yml +0 -47
@@ -1,19 +1,19 @@
|
|
1
1
|
module Raven
|
2
2
|
module ActiveSupportBreadcrumbs
|
3
3
|
class << self
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
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
|
8
|
-
::Logger::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*/)
|
@@ -36,7 +36,7 @@ module Raven
|
|
36
36
|
|
37
37
|
# some loggers will add leading/trailing space as they (incorrectly, mind you)
|
38
38
|
# think of logging as a shortcut to std{out,err}
|
39
|
-
message = message.strip
|
39
|
+
message = message.to_s.strip
|
40
40
|
|
41
41
|
last_crumb = Raven.breadcrumbs.peek
|
42
42
|
# try to avoid dupes from logger broadcasts
|
data/lib/raven/breadcrumbs.rb
CHANGED
data/lib/raven/cli.rb
CHANGED
data/lib/raven/client.rb
CHANGED
@@ -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'
|
10
|
-
USER_AGENT = "raven-ruby/#{Raven::VERSION}"
|
11
|
-
CONTENT_TYPE = 'application/json'
|
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
|
|
@@ -35,7 +38,8 @@ module Raven
|
|
35
38
|
return
|
36
39
|
end
|
37
40
|
|
38
|
-
|
41
|
+
event_id = event[:event_id] || event['event_id']
|
42
|
+
configuration.logger.info "Sending event #{event_id} to Sentry"
|
39
43
|
|
40
44
|
content_type, encoded_data = encode(event)
|
41
45
|
|
@@ -79,8 +83,20 @@ module Raven
|
|
79
83
|
end
|
80
84
|
end
|
81
85
|
|
86
|
+
def get_message_from_exception(event)
|
87
|
+
(
|
88
|
+
event &&
|
89
|
+
event[:exception] &&
|
90
|
+
event[:exception][:values] &&
|
91
|
+
event[:exception][:values][0] &&
|
92
|
+
event[:exception][:values][0][:type] &&
|
93
|
+
event[:exception][:values][0][:value] &&
|
94
|
+
"#{event[:exception][:values][0][:type]}: #{event[:exception][:values][0][:value]}"
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
82
98
|
def get_log_message(event)
|
83
|
-
(event && event[:message]) || '<no message value>'
|
99
|
+
(event && event[:message]) || (event && event['message']) || get_message_from_exception(event) || '<no message value>'
|
84
100
|
end
|
85
101
|
|
86
102
|
def generate_auth_header
|
@@ -100,14 +116,16 @@ module Raven
|
|
100
116
|
end
|
101
117
|
|
102
118
|
def failed_send(e, event)
|
103
|
-
@state.failure
|
104
119
|
if e # exception was raised
|
105
|
-
|
120
|
+
@state.failure
|
121
|
+
configuration.logger.warn "Unable to record event with remote Sentry server (#{e.class} - #{e.message}):\n#{e.backtrace[0..10].join("\n")}"
|
106
122
|
else
|
107
|
-
configuration.logger.
|
123
|
+
configuration.logger.warn "Not sending event due to previous failure(s)."
|
108
124
|
end
|
109
|
-
configuration.logger.
|
110
|
-
|
125
|
+
configuration.logger.warn("Failed to submit event: #{get_log_message(event)}")
|
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
|
111
129
|
end
|
112
130
|
end
|
113
131
|
|
data/lib/raven/configuration.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'uri'
|
2
2
|
|
3
3
|
module Raven
|
4
|
-
class Configuration
|
4
|
+
class Configuration
|
5
5
|
# Directories to be recognized as part of your app. e.g. if you
|
6
6
|
# have an `engines` dir at the root of your project, you may want
|
7
7
|
# to set this to something like /(app|config|engines|lib)/
|
@@ -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
|
257
|
-
@server
|
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
|
|
@@ -347,11 +353,12 @@ module Raven
|
|
347
353
|
end
|
348
354
|
|
349
355
|
def detect_release
|
350
|
-
|
356
|
+
detect_release_from_env ||
|
357
|
+
detect_release_from_git ||
|
351
358
|
detect_release_from_capistrano ||
|
352
359
|
detect_release_from_heroku
|
353
|
-
rescue =>
|
354
|
-
logger.error "Error detecting release: #{
|
360
|
+
rescue => e
|
361
|
+
logger.error "Error detecting release: #{e.message}"
|
355
362
|
end
|
356
363
|
|
357
364
|
def excluded_exception?(incoming_exception)
|
@@ -411,20 +418,27 @@ module Raven
|
|
411
418
|
Raven.sys_command("git rev-parse --short HEAD") if File.directory?(".git")
|
412
419
|
end
|
413
420
|
|
421
|
+
def detect_release_from_env
|
422
|
+
ENV['SENTRY_RELEASE']
|
423
|
+
end
|
424
|
+
|
414
425
|
def capture_in_current_environment?
|
415
426
|
return true unless environments.any? && !environments.include?(current_environment)
|
427
|
+
|
416
428
|
@errors << "Not configured to send/capture in environment '#{current_environment}'"
|
417
429
|
false
|
418
430
|
end
|
419
431
|
|
420
432
|
def capture_allowed_by_callback?(message_or_exc)
|
421
|
-
return true if !should_capture || message_or_exc.nil? || should_capture.call(
|
433
|
+
return true if !should_capture || message_or_exc.nil? || should_capture.call(message_or_exc)
|
434
|
+
|
422
435
|
@errors << "should_capture returned false"
|
423
436
|
false
|
424
437
|
end
|
425
438
|
|
426
439
|
def valid?
|
427
440
|
return true if %w(server host path public_key project_id).all? { |k| public_send(k) }
|
441
|
+
|
428
442
|
if server
|
429
443
|
%w(server host path public_key project_id).map do |key|
|
430
444
|
@errors << "No #{key} specified" unless public_send(key)
|
@@ -437,6 +451,7 @@ module Raven
|
|
437
451
|
|
438
452
|
def sample_allowed?
|
439
453
|
return true if sample_rate == 1.0
|
454
|
+
|
440
455
|
if Random::DEFAULT.rand >= sample_rate
|
441
456
|
@errors << "Excluded by random sample"
|
442
457
|
false
|
@@ -453,7 +468,7 @@ module Raven
|
|
453
468
|
end
|
454
469
|
|
455
470
|
def current_environment_from_env
|
456
|
-
ENV['SENTRY_CURRENT_ENV'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
|
471
|
+
ENV['SENTRY_CURRENT_ENV'] || ENV['SENTRY_ENVIRONMENT'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
|
457
472
|
end
|
458
473
|
|
459
474
|
def server_name_from_env
|
data/lib/raven/event.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'socket'
|
3
4
|
require 'securerandom'
|
4
5
|
|
@@ -59,10 +60,7 @@ module Raven
|
|
59
60
|
return unless configuration.exception_class_allowed?(exc)
|
60
61
|
|
61
62
|
new(options) do |evt|
|
62
|
-
evt.message = "#{exc.class}: #{exc.message}"
|
63
|
-
|
64
63
|
evt.add_exception_interface(exc)
|
65
|
-
|
66
64
|
yield evt if block
|
67
65
|
end
|
68
66
|
end
|
@@ -79,7 +77,7 @@ module Raven
|
|
79
77
|
end
|
80
78
|
|
81
79
|
def message
|
82
|
-
@interfaces[:logentry]
|
80
|
+
@interfaces[:logentry]&.unformatted_message
|
83
81
|
end
|
84
82
|
|
85
83
|
def message=(args)
|
@@ -99,12 +97,13 @@ module Raven
|
|
99
97
|
end
|
100
98
|
|
101
99
|
def level=(new_level) # needed to meet the Sentry spec
|
102
|
-
@level = new_level == "warn"
|
100
|
+
@level = new_level.to_s == "warn" ? :warning : new_level
|
103
101
|
end
|
104
102
|
|
105
103
|
def interface(name, value = nil, &block)
|
106
104
|
int = Interface.registered[name]
|
107
105
|
raise(Error, "Unknown interface: #{name}") unless int
|
106
|
+
|
108
107
|
@interfaces[int.sentry_alias] = int.new(value, &block) if value || block
|
109
108
|
@interfaces[int.sentry_alias]
|
110
109
|
end
|
@@ -231,10 +230,7 @@ module Raven
|
|
231
230
|
end
|
232
231
|
|
233
232
|
def async_json_processors
|
234
|
-
|
235
|
-
Raven::Processor::RemoveCircularReferences,
|
236
|
-
Raven::Processor::UTF8Conversion
|
237
|
-
].map { |v| v.new(self) }
|
233
|
+
configuration.processors.map { |v| v.new(self) }
|
238
234
|
end
|
239
235
|
|
240
236
|
def list_gem_specs
|
data/lib/raven/instance.rb
CHANGED
@@ -51,6 +51,7 @@ module Raven
|
|
51
51
|
# Tell the log that the client is good to go
|
52
52
|
def report_status
|
53
53
|
return if configuration.silence_ready
|
54
|
+
|
54
55
|
if configuration.capture_allowed?
|
55
56
|
logger.info "Raven #{VERSION} ready to catch errors"
|
56
57
|
else
|
@@ -111,15 +112,15 @@ module Raven
|
|
111
112
|
message_or_exc = obj.is_a?(String) ? "message" : "exception"
|
112
113
|
options[:configuration] = configuration
|
113
114
|
options[:context] = context
|
114
|
-
if
|
115
|
+
if evt = Event.send("from_" + message_or_exc, obj, options)
|
115
116
|
yield evt if block_given?
|
116
117
|
if configuration.async?
|
117
118
|
begin
|
118
119
|
# We have to convert to a JSON-like hash, because background job
|
119
120
|
# processors (esp ActiveJob) may not like weird types in the event hash
|
120
121
|
configuration.async.call(evt.to_json_compatible)
|
121
|
-
rescue =>
|
122
|
-
logger.error("async event sending failed: #{
|
122
|
+
rescue => e
|
123
|
+
logger.error("async event sending failed: #{e.message}")
|
123
124
|
send_event(evt, make_hint(obj))
|
124
125
|
end
|
125
126
|
else
|
@@ -183,6 +184,10 @@ module Raven
|
|
183
184
|
# Raven.tags_context('my_custom_tag' => 'tag_value')
|
184
185
|
def tags_context(options = nil)
|
185
186
|
context.tags.merge!(options || {})
|
187
|
+
yield if block_given?
|
188
|
+
context.tags
|
189
|
+
ensure
|
190
|
+
context.tags.delete_if { |k, _| options.keys.include? k } if block_given?
|
186
191
|
end
|
187
192
|
|
188
193
|
# Bind extra context. Merges with existing context (if any).
|
@@ -194,6 +199,10 @@ module Raven
|
|
194
199
|
# Raven.extra_context('my_custom_data' => 'value')
|
195
200
|
def extra_context(options = nil)
|
196
201
|
context.extra.merge!(options || {})
|
202
|
+
yield if block_given?
|
203
|
+
context.extra
|
204
|
+
ensure
|
205
|
+
context.extra.delete_if { |k, _| options.keys.include? k } if block_given?
|
197
206
|
end
|
198
207
|
|
199
208
|
def rack_context(env)
|
@@ -8,19 +8,18 @@ module Delayed
|
|
8
8
|
begin
|
9
9
|
# Forward the call to the next callback in the callback chain
|
10
10
|
block.call(job, *args)
|
11
|
-
|
12
|
-
rescue Exception => exception
|
11
|
+
rescue Exception => e
|
13
12
|
# Log error to Sentry
|
14
13
|
extra = {
|
15
14
|
:delayed_job => {
|
16
|
-
:id
|
17
|
-
:priority
|
18
|
-
:attempts
|
19
|
-
:run_at
|
20
|
-
:locked_at
|
21
|
-
:locked_by
|
22
|
-
:queue
|
23
|
-
:created_at
|
15
|
+
:id => job.id.to_s,
|
16
|
+
:priority => job.priority,
|
17
|
+
:attempts => job.attempts,
|
18
|
+
:run_at => job.run_at,
|
19
|
+
:locked_at => job.locked_at,
|
20
|
+
:locked_by => job.locked_by,
|
21
|
+
:queue => job.queue,
|
22
|
+
:created_at => job.created_at
|
24
23
|
}
|
25
24
|
}
|
26
25
|
# last_error can be nil
|
@@ -32,16 +31,16 @@ module Delayed
|
|
32
31
|
if job.respond_to?('payload_object') && job.payload_object.respond_to?('job_data')
|
33
32
|
extra[:active_job] = job.payload_object.job_data
|
34
33
|
end
|
35
|
-
::Raven.capture_exception(
|
36
|
-
:logger
|
37
|
-
:tags
|
34
|
+
::Raven.capture_exception(e,
|
35
|
+
:logger => 'delayed_job',
|
36
|
+
:tags => {
|
38
37
|
:delayed_job_queue => job.queue,
|
39
|
-
:delayed_job_id => job.id
|
38
|
+
:delayed_job_id => job.id.to_s
|
40
39
|
},
|
41
40
|
:extra => extra)
|
42
41
|
|
43
42
|
# Make sure we propagate the failure!
|
44
|
-
raise
|
43
|
+
raise e
|
45
44
|
ensure
|
46
45
|
::Raven::Context.clear!
|
47
46
|
::Raven::BreadcrumbBuffer.clear!
|
@@ -14,6 +14,5 @@ module RackTimeoutExtensions
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
Rack::Timeout::
|
19
|
-
Rack::Timeout::RequestTimeoutException.__send__(:include, RackTimeoutExtensions)
|
17
|
+
Rack::Timeout::Error.include(RackTimeoutExtensions)
|
18
|
+
Rack::Timeout::RequestTimeoutException.include(RackTimeoutExtensions)
|
@@ -92,8 +92,8 @@ module Raven
|
|
92
92
|
request.body.rewind
|
93
93
|
data
|
94
94
|
end
|
95
|
-
rescue IOError =>
|
96
|
-
|
95
|
+
rescue IOError => e
|
96
|
+
e.message
|
97
97
|
end
|
98
98
|
|
99
99
|
def format_headers_for_sentry(env_hash)
|
@@ -112,8 +112,9 @@ module Raven
|
|
112
112
|
next if key == 'HTTP_COOKIE' # Cookies don't go here, they go somewhere else
|
113
113
|
|
114
114
|
next unless key.start_with?('HTTP_') || %w(CONTENT_TYPE CONTENT_LENGTH).include?(key)
|
115
|
+
|
115
116
|
# Rack stores headers as HTTP_WHAT_EVER, we need What-Ever
|
116
|
-
key = key.
|
117
|
+
key = key.sub(/^HTTP_/, "")
|
117
118
|
key = key.split('_').map(&:capitalize).join('-')
|
118
119
|
memo[key] = value
|
119
120
|
rescue StandardError => e
|