sentry-raven 2.13.0 → 3.1.2
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/.craft.yml +19 -0
- data/.scripts/bump-version.rb +5 -0
- data/{changelog.md → CHANGELOG.md} +182 -1
- data/Gemfile +24 -25
- data/Makefile +3 -0
- data/README.md +44 -16
- data/lib/raven/backtrace.rb +9 -5
- data/lib/raven/base.rb +7 -2
- data/lib/raven/breadcrumbs/{activesupport.rb → active_support_logger.rb} +9 -3
- data/lib/raven/breadcrumbs/logger.rb +2 -92
- data/lib/raven/breadcrumbs/sentry_logger.rb +73 -0
- data/lib/raven/breadcrumbs.rb +1 -1
- data/lib/raven/cli.rb +10 -21
- data/lib/raven/client.rb +9 -4
- data/lib/raven/configuration.rb +95 -10
- data/lib/raven/context.rb +13 -8
- data/lib/raven/core_ext/object/deep_dup.rb +57 -0
- data/lib/raven/core_ext/object/duplicable.rb +153 -0
- data/lib/raven/event.rb +31 -15
- data/lib/raven/helpers/deprecation_helper.rb +17 -0
- data/lib/raven/instance.rb +21 -5
- data/lib/raven/integrations/delayed_job.rb +15 -15
- data/lib/raven/integrations/rack-timeout.rb +7 -4
- data/lib/raven/integrations/rack.rb +9 -7
- data/lib/raven/integrations/rails/active_job.rb +6 -4
- data/lib/raven/integrations/rails/backtrace_cleaner.rb +29 -0
- data/lib/raven/integrations/rails/overrides/debug_exceptions_catcher.rb +2 -2
- data/lib/raven/integrations/rails.rb +13 -3
- data/lib/raven/integrations/sidekiq/cleanup_middleware.rb +13 -0
- data/lib/raven/integrations/sidekiq/error_handler.rb +38 -0
- data/lib/raven/integrations/sidekiq.rb +4 -78
- 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 +3 -1
- data/lib/raven/processor/sanitizedata.rb +65 -17
- data/lib/raven/processor/utf8conversion.rb +2 -0
- data/lib/raven/transports/http.rb +7 -8
- data/lib/raven/transports.rb +4 -0
- data/lib/raven/utils/context_filter.rb +42 -0
- data/lib/raven/utils/exception_cause_chain.rb +1 -0
- data/lib/raven/utils/real_ip.rb +1 -1
- data/lib/raven/utils/request_id.rb +16 -0
- data/lib/raven/version.rb +2 -2
- data/lib/sentry-raven-without-integrations.rb +6 -1
- data/lib/sentry_raven_without_integrations.rb +1 -0
- data/sentry-raven.gemspec +9 -2
- metadata +23 -17
- data/.gitignore +0 -13
- data/.gitmodules +0 -0
- data/.rspec +0 -1
- data/.rubocop.yml +0 -74
- data/.travis.yml +0 -47
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
|
|
@@ -7,6 +8,7 @@ module Raven
|
|
7
8
|
# See Sentry server default limits at
|
8
9
|
# https://github.com/getsentry/sentry/blob/master/src/sentry/conf/server.py
|
9
10
|
MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
|
11
|
+
REQUIRED_OPTION_KEYS = [:configuration, :context, :breadcrumbs].freeze
|
10
12
|
|
11
13
|
SDK = { "name" => "raven-ruby", "version" => Raven::VERSION }.freeze
|
12
14
|
|
@@ -18,7 +20,7 @@ module Raven
|
|
18
20
|
|
19
21
|
attr_reader :level, :timestamp, :time_spent
|
20
22
|
|
21
|
-
def initialize(
|
23
|
+
def initialize(options)
|
22
24
|
# Set some simple default values
|
23
25
|
self.id = SecureRandom.uuid.delete("-")
|
24
26
|
self.timestamp = Time.now.utc
|
@@ -35,11 +37,17 @@ module Raven
|
|
35
37
|
self.runtime = {} # TODO: contexts
|
36
38
|
self.tags = {} # TODO: contexts
|
37
39
|
|
38
|
-
|
40
|
+
unless REQUIRED_OPTION_KEYS.all? { |key| options.key?(key) }
|
41
|
+
raise "you must provide configuration, context, and breadcrumbs when initializing a Raven::Event"
|
42
|
+
end
|
43
|
+
|
44
|
+
self.configuration = options[:configuration]
|
45
|
+
self.context = options[:context]
|
46
|
+
self.breadcrumbs = options[:breadcrumbs]
|
39
47
|
|
40
48
|
# Allow attributes to be set on the event at initialization
|
41
49
|
yield self if block_given?
|
42
|
-
|
50
|
+
options.each_pair { |key, val| public_send("#{key}=", val) unless val.nil? }
|
43
51
|
|
44
52
|
set_core_attributes_from_configuration
|
45
53
|
set_core_attributes_from_context
|
@@ -55,8 +63,7 @@ module Raven
|
|
55
63
|
end
|
56
64
|
options = Raven::Utils::DeepMergeHash.deep_merge(exception_context, options)
|
57
65
|
|
58
|
-
|
59
|
-
return unless configuration.exception_class_allowed?(exc)
|
66
|
+
return unless options[:configuration].exception_class_allowed?(exc)
|
60
67
|
|
61
68
|
new(options) do |evt|
|
62
69
|
evt.add_exception_interface(exc)
|
@@ -76,11 +83,21 @@ module Raven
|
|
76
83
|
end
|
77
84
|
|
78
85
|
def message
|
79
|
-
@interfaces[:logentry]
|
86
|
+
@interfaces[:logentry]&.unformatted_message
|
80
87
|
end
|
81
88
|
|
82
89
|
def message=(args)
|
83
|
-
|
90
|
+
if args.is_a?(Array)
|
91
|
+
message, params = args[0], args[0..-1]
|
92
|
+
else
|
93
|
+
message = args
|
94
|
+
end
|
95
|
+
|
96
|
+
unless message.is_a?(String)
|
97
|
+
configuration.logger.debug("You're passing a non-string message")
|
98
|
+
message = message.to_s
|
99
|
+
end
|
100
|
+
|
84
101
|
interface(:message) do |int|
|
85
102
|
int.message = message.byteslice(0...MAX_MESSAGE_SIZE_IN_BYTES) # Messages limited to 10kb
|
86
103
|
int.params = params
|
@@ -96,12 +113,13 @@ module Raven
|
|
96
113
|
end
|
97
114
|
|
98
115
|
def level=(new_level) # needed to meet the Sentry spec
|
99
|
-
@level = new_level == "warn"
|
116
|
+
@level = new_level.to_s == "warn" ? :warning : new_level
|
100
117
|
end
|
101
118
|
|
102
119
|
def interface(name, value = nil, &block)
|
103
120
|
int = Interface.registered[name]
|
104
121
|
raise(Error, "Unknown interface: #{name}") unless int
|
122
|
+
|
105
123
|
@interfaces[int.sentry_alias] = int.new(value, &block) if value || block
|
106
124
|
@interfaces[int.sentry_alias]
|
107
125
|
end
|
@@ -157,7 +175,7 @@ module Raven
|
|
157
175
|
end
|
158
176
|
|
159
177
|
def stacktrace_interface_from(backtrace)
|
160
|
-
Backtrace.parse(backtrace).lines.reverse.each_with_object([]) do |line, memo|
|
178
|
+
Backtrace.parse(backtrace, { configuration: configuration }).lines.reverse.each_with_object([]) do |line, memo|
|
161
179
|
frame = StacktraceInterface::Frame.new
|
162
180
|
frame.abs_path = line.file if line.file
|
163
181
|
frame.function = line.method if line.method
|
@@ -184,12 +202,6 @@ module Raven
|
|
184
202
|
|
185
203
|
private
|
186
204
|
|
187
|
-
def copy_initial_state
|
188
|
-
self.configuration = Raven.configuration
|
189
|
-
self.breadcrumbs = Raven.breadcrumbs
|
190
|
-
self.context = Raven.context
|
191
|
-
end
|
192
|
-
|
193
205
|
def set_core_attributes_from_configuration
|
194
206
|
self.server_name ||= configuration.server_name
|
195
207
|
self.release ||= configuration.release
|
@@ -214,6 +226,10 @@ module Raven
|
|
214
226
|
int.from_rack(context.rack_env)
|
215
227
|
end
|
216
228
|
context.user[:ip_address] = calculate_real_ip_from_rack
|
229
|
+
|
230
|
+
if request_id = Utils::RequestId.read_from(context.rack_env)
|
231
|
+
context.tags[:request_id] = request_id
|
232
|
+
end
|
217
233
|
end
|
218
234
|
|
219
235
|
# When behind a proxy (or if the user is using a proxy), we can't use
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module DeprecationHelper
|
2
|
+
def self.deprecate_dasherized_filename(correct_filename)
|
3
|
+
warn "[Deprecation Warning] Dasherized filename \"#{correct_filename.gsub('_', '-')}\" is deprecated and will be removed in 4.0; use \"#{correct_filename}\" instead" # rubocop:disable Style/LineLength
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.deprecate_old_breadcrumbs_configuration(logger)
|
7
|
+
deprecated_usage =
|
8
|
+
if logger == :sentry_logger
|
9
|
+
"require \"raven/breadcrumbs/logger\""
|
10
|
+
else
|
11
|
+
"Raven.configuration.rails_activesupport_breadcrumbs = true"
|
12
|
+
end
|
13
|
+
recommended_usage = "Raven.configuration.breadcrumbs_logger = :#{logger}"
|
14
|
+
|
15
|
+
warn "[Deprecation Warning] The way you enable breadcrumbs logger (#{deprecated_usage}) is deprecated and will be removed in 4.0; use '#{recommended_usage}' instead" # rubocop:disable Style/LineLength
|
16
|
+
end
|
17
|
+
end
|
data/lib/raven/instance.rb
CHANGED
@@ -50,7 +50,9 @@ module Raven
|
|
50
50
|
|
51
51
|
# Tell the log that the client is good to go
|
52
52
|
def report_status
|
53
|
+
return unless configuration.enabled_in_current_env?
|
53
54
|
return if configuration.silence_ready
|
55
|
+
|
54
56
|
if configuration.capture_allowed?
|
55
57
|
logger.info "Raven #{VERSION} ready to catch errors"
|
56
58
|
else
|
@@ -75,7 +77,7 @@ module Raven
|
|
75
77
|
# Send an event to the configured Sentry server
|
76
78
|
#
|
77
79
|
# @example
|
78
|
-
# evt = Raven::Event.new(:message => "An
|
80
|
+
# evt = Raven::Event.new(:message => "An errore)
|
79
81
|
# Raven.send_event(evt)
|
80
82
|
def send_event(event, hint = nil)
|
81
83
|
client.send_event(event, hint)
|
@@ -109,17 +111,20 @@ module Raven
|
|
109
111
|
end
|
110
112
|
|
111
113
|
message_or_exc = obj.is_a?(String) ? "message" : "exception"
|
114
|
+
options = options.deep_dup
|
112
115
|
options[:configuration] = configuration
|
113
116
|
options[:context] = context
|
114
|
-
|
117
|
+
options[:breadcrumbs] = breadcrumbs
|
118
|
+
|
119
|
+
if evt = Event.send("from_" + message_or_exc, obj, options)
|
115
120
|
yield evt if block_given?
|
116
121
|
if configuration.async?
|
117
122
|
begin
|
118
123
|
# We have to convert to a JSON-like hash, because background job
|
119
124
|
# processors (esp ActiveJob) may not like weird types in the event hash
|
120
125
|
configuration.async.call(evt.to_json_compatible)
|
121
|
-
rescue =>
|
122
|
-
logger.error("async event sending failed: #{
|
126
|
+
rescue => e
|
127
|
+
logger.error("async event sending failed: #{e.message}")
|
123
128
|
send_event(evt, make_hint(obj))
|
124
129
|
end
|
125
130
|
else
|
@@ -171,7 +176,18 @@ module Raven
|
|
171
176
|
# @example
|
172
177
|
# Raven.user_context('id' => 1, 'email' => 'foo@example.com')
|
173
178
|
def user_context(options = nil)
|
174
|
-
context.user
|
179
|
+
original_user_context = context.user
|
180
|
+
|
181
|
+
if options
|
182
|
+
context.user.merge!(options)
|
183
|
+
else
|
184
|
+
context.user = {}
|
185
|
+
end
|
186
|
+
|
187
|
+
yield if block_given?
|
188
|
+
context.user
|
189
|
+
ensure
|
190
|
+
context.user = original_user_context if block_given?
|
175
191
|
end
|
176
192
|
|
177
193
|
# Bind tags context. Merges with existing context (if any).
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'delayed_job'
|
2
|
+
require 'raven/utils/context_filter'
|
2
3
|
|
3
4
|
module Delayed
|
4
5
|
module Plugins
|
@@ -8,19 +9,18 @@ module Delayed
|
|
8
9
|
begin
|
9
10
|
# Forward the call to the next callback in the callback chain
|
10
11
|
block.call(job, *args)
|
11
|
-
|
12
|
-
rescue Exception => exception
|
12
|
+
rescue Exception => e
|
13
13
|
# Log error to Sentry
|
14
14
|
extra = {
|
15
15
|
:delayed_job => {
|
16
|
-
:id
|
17
|
-
:priority
|
18
|
-
:attempts
|
19
|
-
:run_at
|
20
|
-
:locked_at
|
21
|
-
:locked_by
|
22
|
-
:queue
|
23
|
-
:created_at
|
16
|
+
:id => job.id.to_s,
|
17
|
+
:priority => job.priority,
|
18
|
+
:attempts => job.attempts,
|
19
|
+
:run_at => job.run_at,
|
20
|
+
:locked_at => job.locked_at,
|
21
|
+
:locked_by => job.locked_by,
|
22
|
+
:queue => job.queue,
|
23
|
+
:created_at => job.created_at
|
24
24
|
}
|
25
25
|
}
|
26
26
|
# last_error can be nil
|
@@ -30,18 +30,18 @@ module Delayed
|
|
30
30
|
extra[:handler] = job.handler[0...1000] if job.handler
|
31
31
|
|
32
32
|
if job.respond_to?('payload_object') && job.payload_object.respond_to?('job_data')
|
33
|
-
extra[:active_job] = job.payload_object.job_data
|
33
|
+
extra[:active_job] = ::Raven::Utils::ContextFilter.filter_context(job.payload_object.job_data)
|
34
34
|
end
|
35
|
-
::Raven.capture_exception(
|
36
|
-
:logger
|
37
|
-
:tags
|
35
|
+
::Raven.capture_exception(e,
|
36
|
+
:logger => 'delayed_job',
|
37
|
+
:tags => {
|
38
38
|
:delayed_job_queue => job.queue,
|
39
39
|
:delayed_job_id => job.id.to_s
|
40
40
|
},
|
41
41
|
:extra => extra)
|
42
42
|
|
43
43
|
# Make sure we propagate the failure!
|
44
|
-
raise
|
44
|
+
raise e
|
45
45
|
ensure
|
46
46
|
::Raven::Context.clear!
|
47
47
|
::Raven::BreadcrumbBuffer.clear!
|
@@ -10,10 +10,13 @@ module RackTimeoutExtensions
|
|
10
10
|
# Only rack-timeout 0.3.0+ provides the request environment, but we can't
|
11
11
|
# gate this based on a gem version constant because rack-timeout does
|
12
12
|
# not provide one.
|
13
|
-
|
13
|
+
if defined?(env)
|
14
|
+
{ :fingerprint => ["{{ default }}", env["REQUEST_URI"]] }
|
15
|
+
else
|
16
|
+
{}
|
17
|
+
end
|
14
18
|
end
|
15
19
|
end
|
16
20
|
|
17
|
-
|
18
|
-
Rack::Timeout::
|
19
|
-
Rack::Timeout::RequestTimeoutException.__send__(:include, RackTimeoutExtensions)
|
21
|
+
Rack::Timeout::Error.include(RackTimeoutExtensions)
|
22
|
+
Rack::Timeout::RequestTimeoutException.include(RackTimeoutExtensions)
|
@@ -92,15 +92,15 @@ 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)
|
100
100
|
env_hash.each_with_object({}) do |(key, value), memo|
|
101
101
|
begin
|
102
102
|
key = key.to_s # rack env can contain symbols
|
103
|
-
|
103
|
+
next memo['X-Request-Id'] ||= Utils::RequestId.read_from(env_hash) if Utils::RequestId::REQUEST_ID_HEADERS.include?(key)
|
104
104
|
next unless key.upcase == key # Non-upper case stuff isn't either
|
105
105
|
|
106
106
|
# Rack adds in an incorrect HTTP_VERSION key, which causes downstream
|
@@ -110,12 +110,12 @@ module Raven
|
|
110
110
|
# See: https://github.com/rack/rack/blob/028438f/lib/rack/handler/cgi.rb#L29
|
111
111
|
next if key == 'HTTP_VERSION' && value == env_hash['SERVER_PROTOCOL']
|
112
112
|
next if key == 'HTTP_COOKIE' # Cookies don't go here, they go somewhere else
|
113
|
-
|
114
113
|
next unless key.start_with?('HTTP_') || %w(CONTENT_TYPE CONTENT_LENGTH).include?(key)
|
114
|
+
|
115
115
|
# Rack stores headers as HTTP_WHAT_EVER, we need What-Ever
|
116
|
-
key = key.
|
116
|
+
key = key.sub(/^HTTP_/, "")
|
117
117
|
key = key.split('_').map(&:capitalize).join('-')
|
118
|
-
memo[key] = value
|
118
|
+
memo[key] = value.to_s
|
119
119
|
rescue StandardError => e
|
120
120
|
# Rails adds objects to the Rack env that can sometimes raise exceptions
|
121
121
|
# when `to_s` is called.
|
@@ -127,8 +127,10 @@ module Raven
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def format_env_for_sentry(env_hash)
|
130
|
+
return env_hash if Raven.configuration.rack_env_whitelist.empty?
|
131
|
+
|
130
132
|
env_hash.select do |k, _v|
|
131
|
-
|
133
|
+
Raven.configuration.rack_env_whitelist.include? k.to_s
|
132
134
|
end
|
133
135
|
end
|
134
136
|
end
|
@@ -20,10 +20,12 @@ module Raven
|
|
20
20
|
|
21
21
|
def capture_and_reraise_with_sentry(job, block)
|
22
22
|
block.call
|
23
|
-
rescue Exception =>
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
24
|
+
rescue_handler_result = rescue_with_handler(e)
|
25
|
+
return rescue_handler_result if rescue_handler_result
|
26
|
+
|
27
|
+
Raven.capture_exception(e, :extra => raven_context(job))
|
28
|
+
raise e
|
27
29
|
ensure
|
28
30
|
Context.clear!
|
29
31
|
BreadcrumbBuffer.clear!
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "active_support/backtrace_cleaner"
|
2
|
+
require "active_support/core_ext/string/access"
|
3
|
+
|
4
|
+
module Raven
|
5
|
+
class Rails
|
6
|
+
class BacktraceCleaner < ActiveSupport::BacktraceCleaner
|
7
|
+
APP_DIRS_PATTERN = /\A(?:\.\/)?(?:app|config|lib|test|\(\w*\))/.freeze
|
8
|
+
RENDER_TEMPLATE_PATTERN = /:in `.*_\w+_{2,3}\d+_\d+'/.freeze
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super
|
12
|
+
# we don't want any default silencers because they're too aggressive
|
13
|
+
remove_silencers!
|
14
|
+
|
15
|
+
@root = "#{Raven.configuration.project_root}/"
|
16
|
+
add_filter do |line|
|
17
|
+
line.start_with?(@root) ? line.from(@root.size) : line
|
18
|
+
end
|
19
|
+
add_filter do |line|
|
20
|
+
if line =~ RENDER_TEMPLATE_PATTERN
|
21
|
+
line.sub(RENDER_TEMPLATE_PATTERN, "")
|
22
|
+
else
|
23
|
+
line
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -6,7 +6,7 @@ module Raven
|
|
6
6
|
begin
|
7
7
|
env = env_or_request.respond_to?(:env) ? env_or_request.env : env_or_request
|
8
8
|
Raven::Rack.capture_exception(exception, env)
|
9
|
-
rescue
|
9
|
+
rescue
|
10
10
|
end
|
11
11
|
super
|
12
12
|
end
|
@@ -21,7 +21,7 @@ module Raven
|
|
21
21
|
begin
|
22
22
|
env = env_or_request.respond_to?(:env) ? env_or_request.env : env_or_request
|
23
23
|
Raven::Rack.capture_exception(exception, env)
|
24
|
-
rescue
|
24
|
+
rescue
|
25
25
|
end
|
26
26
|
render_exception_without_raven(env_or_request, exception)
|
27
27
|
end
|
@@ -5,6 +5,8 @@ module Raven
|
|
5
5
|
require 'raven/integrations/rails/overrides/streaming_reporter'
|
6
6
|
require 'raven/integrations/rails/controller_methods'
|
7
7
|
require 'raven/integrations/rails/controller_transaction'
|
8
|
+
require 'raven/integrations/rails/backtrace_cleaner'
|
9
|
+
require 'raven/integrations/rack'
|
8
10
|
|
9
11
|
initializer "raven.use_rack_middleware" do |app|
|
10
12
|
app.config.middleware.insert 0, Raven::Rack
|
@@ -36,12 +38,20 @@ module Raven
|
|
36
38
|
|
37
39
|
config.before_initialize do
|
38
40
|
Raven.configuration.logger = ::Rails.logger
|
41
|
+
|
42
|
+
backtrace_cleaner = Raven::Rails::BacktraceCleaner.new
|
43
|
+
|
44
|
+
Raven.configuration.backtrace_cleanup_callback = lambda do |backtrace|
|
45
|
+
backtrace_cleaner.clean(backtrace)
|
46
|
+
end
|
39
47
|
end
|
40
48
|
|
41
49
|
config.after_initialize do
|
42
|
-
if Raven.configuration.
|
43
|
-
|
44
|
-
|
50
|
+
if Raven.configuration.breadcrumbs_logger.include?(:active_support_logger) ||
|
51
|
+
Raven.configuration.rails_activesupport_breadcrumbs
|
52
|
+
|
53
|
+
require 'raven/breadcrumbs/active_support_logger'
|
54
|
+
Raven::Breadcrumbs::ActiveSupportLogger.inject
|
45
55
|
end
|
46
56
|
|
47
57
|
if Raven.configuration.rails_report_rescued_exceptions
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Raven
|
2
|
+
module Sidekiq
|
3
|
+
class CleanupMiddleware
|
4
|
+
def call(_worker, job, queue)
|
5
|
+
Raven.context.transaction.push "Sidekiq/#{job['class']}"
|
6
|
+
Raven.extra_context(:sidekiq => job.merge("queue" => queue))
|
7
|
+
yield
|
8
|
+
Context.clear!
|
9
|
+
BreadcrumbBuffer.clear!
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'raven/utils/context_filter'
|
2
|
+
|
3
|
+
module Raven
|
4
|
+
module Sidekiq
|
5
|
+
class ErrorHandler
|
6
|
+
SIDEKIQ_NAME = "Sidekiq".freeze
|
7
|
+
|
8
|
+
def call(ex, context)
|
9
|
+
context = Utils::ContextFilter.filter_context(context)
|
10
|
+
Raven.context.transaction.push transaction_from_context(context)
|
11
|
+
Raven.capture_exception(
|
12
|
+
ex,
|
13
|
+
:message => ex.message,
|
14
|
+
:extra => { :sidekiq => context }
|
15
|
+
)
|
16
|
+
Context.clear!
|
17
|
+
BreadcrumbBuffer.clear!
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# this will change in the future:
|
23
|
+
# https://github.com/mperham/sidekiq/pull/3161
|
24
|
+
def transaction_from_context(context)
|
25
|
+
classname = (context["wrapped"] || context["class"] ||
|
26
|
+
(context[:job] && (context[:job]["wrapped"] || context[:job]["class"]))
|
27
|
+
)
|
28
|
+
if classname
|
29
|
+
"#{SIDEKIQ_NAME}/#{classname}"
|
30
|
+
elsif context[:event]
|
31
|
+
"#{SIDEKIQ_NAME}/#{context[:event]}"
|
32
|
+
else
|
33
|
+
SIDEKIQ_NAME
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,87 +1,13 @@
|
|
1
1
|
require 'time'
|
2
2
|
require 'sidekiq'
|
3
|
-
|
4
|
-
|
5
|
-
class SidekiqCleanupMiddleware
|
6
|
-
def call(_worker, job, queue)
|
7
|
-
Raven.context.transaction.push "Sidekiq/#{job['class']}"
|
8
|
-
Raven.extra_context(:sidekiq => job.merge("queue" => queue))
|
9
|
-
yield
|
10
|
-
Context.clear!
|
11
|
-
BreadcrumbBuffer.clear!
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
class SidekiqErrorHandler
|
16
|
-
ACTIVEJOB_RESERVED_PREFIX = "_aj_".freeze
|
17
|
-
HAS_GLOBALID = const_defined?('GlobalID')
|
18
|
-
|
19
|
-
def call(ex, context)
|
20
|
-
context = filter_context(context)
|
21
|
-
Raven.context.transaction.push transaction_from_context(context)
|
22
|
-
Raven.capture_exception(
|
23
|
-
ex,
|
24
|
-
:message => ex.message,
|
25
|
-
:extra => { :sidekiq => context }
|
26
|
-
)
|
27
|
-
Context.clear!
|
28
|
-
BreadcrumbBuffer.clear!
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
# Once an ActiveJob is queued, ActiveRecord references get serialized into
|
34
|
-
# some internal reserved keys, such as _aj_globalid.
|
35
|
-
#
|
36
|
-
# The problem is, if this job in turn gets queued back into ActiveJob with
|
37
|
-
# these magic reserved keys, ActiveJob will throw up and error. We want to
|
38
|
-
# capture these and mutate the keys so we can sanely report it.
|
39
|
-
def filter_context(context)
|
40
|
-
case context
|
41
|
-
when Array
|
42
|
-
context.map { |arg| filter_context(arg) }
|
43
|
-
when Hash
|
44
|
-
Hash[context.map { |key, value| filter_context_hash(key, value) }]
|
45
|
-
else
|
46
|
-
format_globalid(context)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def filter_context_hash(key, value)
|
51
|
-
(key = key[3..-1]) if key [0..3] == ACTIVEJOB_RESERVED_PREFIX
|
52
|
-
[key, filter_context(value)]
|
53
|
-
end
|
54
|
-
|
55
|
-
# this will change in the future:
|
56
|
-
# https://github.com/mperham/sidekiq/pull/3161
|
57
|
-
def transaction_from_context(context)
|
58
|
-
classname = (context["wrapped"] || context["class"] ||
|
59
|
-
(context[:job] && (context[:job]["wrapped"] || context[:job]["class"]))
|
60
|
-
)
|
61
|
-
if classname
|
62
|
-
"Sidekiq/#{classname}"
|
63
|
-
elsif context[:event]
|
64
|
-
"Sidekiq/#{context[:event]}"
|
65
|
-
else
|
66
|
-
"Sidekiq"
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def format_globalid(context)
|
71
|
-
if HAS_GLOBALID && context.is_a?(GlobalID)
|
72
|
-
context.to_s
|
73
|
-
else
|
74
|
-
context
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
3
|
+
require 'raven/integrations/sidekiq/cleanup_middleware'
|
4
|
+
require 'raven/integrations/sidekiq/error_handler'
|
79
5
|
|
80
6
|
if Sidekiq::VERSION > '3'
|
81
7
|
Sidekiq.configure_server do |config|
|
82
|
-
config.error_handlers << Raven::
|
8
|
+
config.error_handlers << Raven::Sidekiq::ErrorHandler.new
|
83
9
|
config.server_middleware do |chain|
|
84
|
-
chain.add Raven::
|
10
|
+
chain.add Raven::Sidekiq::CleanupMiddleware
|
85
11
|
end
|
86
12
|
end
|
87
13
|
end
|
data/lib/raven/interface.rb
CHANGED
data/lib/raven/linecache.rb
CHANGED
@@ -10,6 +10,7 @@ module Raven
|
|
10
10
|
# line should be the line requested by lineno. See specs for more information.
|
11
11
|
def get_file_context(filename, lineno, context)
|
12
12
|
return nil, nil, nil unless valid_path?(filename)
|
13
|
+
|
13
14
|
lines = Array.new(2 * context + 1) do |i|
|
14
15
|
getline(filename, lineno - context + i)
|
15
16
|
end
|
@@ -26,15 +27,17 @@ module Raven
|
|
26
27
|
def getlines(path)
|
27
28
|
@cache[path] ||= begin
|
28
29
|
IO.readlines(path)
|
29
|
-
|
30
|
-
|
30
|
+
rescue
|
31
|
+
nil
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
34
35
|
def getline(path, n)
|
35
36
|
return nil if n < 1
|
37
|
+
|
36
38
|
lines = getlines(path)
|
37
39
|
return nil if lines.nil?
|
40
|
+
|
38
41
|
lines[n - 1]
|
39
42
|
end
|
40
43
|
end
|
data/lib/raven/logger.rb
CHANGED
@@ -10,17 +10,27 @@ module Raven
|
|
10
10
|
private
|
11
11
|
|
12
12
|
def process_if_symbol_keys(data)
|
13
|
-
|
13
|
+
if cookies = data.dig(:request, :cookies)
|
14
|
+
data[:request][:cookies] = generate_masked_cookies(cookies)
|
15
|
+
end
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
+
if cookies_header = data[:request][:headers]["Cookie"]
|
18
|
+
data[:request][:headers]["Cookie"] = generate_masked_cookies(cookies_header)
|
19
|
+
end
|
17
20
|
end
|
18
21
|
|
19
22
|
def process_if_string_keys(data)
|
20
|
-
|
23
|
+
if cookies = data.dig("request", "cookies")
|
24
|
+
data["request"]["cookies"] = generate_masked_cookies(cookies)
|
25
|
+
end
|
21
26
|
|
22
|
-
|
23
|
-
|
27
|
+
if cookies_header = data.dig("request", "headers", "Cookie")
|
28
|
+
data["request"]["headers"]["Cookie"] = generate_masked_cookies(cookies_header)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def generate_masked_cookies(cookies)
|
33
|
+
cookies.merge(cookies) { STRING_MASK } if cookies.respond_to?(:merge)
|
24
34
|
end
|
25
35
|
end
|
26
36
|
end
|