sentry-raven 3.0.2 → 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 +9 -5
- data/.scripts/bump-version.rb +5 -0
- data/{changelog.md → CHANGELOG.md} +165 -8
- data/Gemfile +10 -3
- data/Makefile +3 -0
- data/README.md +42 -15
- data/lib/raven/backtrace.rb +2 -0
- data/lib/raven/base.rb +3 -0
- data/lib/raven/breadcrumbs/active_support_logger.rb +25 -0
- data/lib/raven/breadcrumbs/logger.rb +2 -92
- data/lib/raven/breadcrumbs/sentry_logger.rb +73 -0
- data/lib/raven/cli.rb +8 -19
- data/lib/raven/client.rb +1 -1
- data/lib/raven/configuration.rb +80 -5
- 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 +27 -13
- data/lib/raven/helpers/deprecation_helper.rb +17 -0
- data/lib/raven/instance.rb +17 -2
- data/lib/raven/integrations/delayed_job.rb +2 -1
- data/lib/raven/integrations/rack-timeout.rb +5 -1
- data/lib/raven/integrations/rack.rb +5 -4
- data/lib/raven/integrations/rails.rb +12 -3
- data/lib/raven/integrations/rails/active_job.rb +2 -1
- data/lib/raven/integrations/rails/backtrace_cleaner.rb +29 -0
- data/lib/raven/integrations/sidekiq.rb +4 -78
- data/lib/raven/integrations/sidekiq/cleanup_middleware.rb +13 -0
- data/lib/raven/integrations/sidekiq/error_handler.rb +38 -0
- data/lib/raven/processor/cookies.rb +1 -1
- data/lib/raven/processor/removecircularreferences.rb +2 -1
- data/lib/raven/transports/http.rb +2 -3
- data/lib/raven/utils/context_filter.rb +42 -0
- data/lib/raven/utils/request_id.rb +16 -0
- data/lib/raven/version.rb +1 -1
- data/lib/sentry-raven-without-integrations.rb +6 -1
- data/lib/sentry_raven_without_integrations.rb +1 -0
- data/sentry-raven.gemspec +7 -0
- metadata +21 -11
- data/.github/workflows/test.yml +0 -77
- data/.gitignore +0 -15
- data/.gitmodules +0 -0
- data/.rspec +0 -1
- data/.rubocop.yml +0 -109
- data/.scripts/bump-version.sh +0 -9
- data/lib/raven/breadcrumbs/activesupport.rb +0 -19
data/lib/raven/event.rb
CHANGED
@@ -8,6 +8,7 @@ module Raven
|
|
8
8
|
# See Sentry server default limits at
|
9
9
|
# https://github.com/getsentry/sentry/blob/master/src/sentry/conf/server.py
|
10
10
|
MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
|
11
|
+
REQUIRED_OPTION_KEYS = [:configuration, :context, :breadcrumbs].freeze
|
11
12
|
|
12
13
|
SDK = { "name" => "raven-ruby", "version" => Raven::VERSION }.freeze
|
13
14
|
|
@@ -19,7 +20,7 @@ module Raven
|
|
19
20
|
|
20
21
|
attr_reader :level, :timestamp, :time_spent
|
21
22
|
|
22
|
-
def initialize(
|
23
|
+
def initialize(options)
|
23
24
|
# Set some simple default values
|
24
25
|
self.id = SecureRandom.uuid.delete("-")
|
25
26
|
self.timestamp = Time.now.utc
|
@@ -36,11 +37,17 @@ module Raven
|
|
36
37
|
self.runtime = {} # TODO: contexts
|
37
38
|
self.tags = {} # TODO: contexts
|
38
39
|
|
39
|
-
|
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]
|
40
47
|
|
41
48
|
# Allow attributes to be set on the event at initialization
|
42
49
|
yield self if block_given?
|
43
|
-
|
50
|
+
options.each_pair { |key, val| public_send("#{key}=", val) unless val.nil? }
|
44
51
|
|
45
52
|
set_core_attributes_from_configuration
|
46
53
|
set_core_attributes_from_context
|
@@ -56,8 +63,7 @@ module Raven
|
|
56
63
|
end
|
57
64
|
options = Raven::Utils::DeepMergeHash.deep_merge(exception_context, options)
|
58
65
|
|
59
|
-
|
60
|
-
return unless configuration.exception_class_allowed?(exc)
|
66
|
+
return unless options[:configuration].exception_class_allowed?(exc)
|
61
67
|
|
62
68
|
new(options) do |evt|
|
63
69
|
evt.add_exception_interface(exc)
|
@@ -81,7 +87,17 @@ module Raven
|
|
81
87
|
end
|
82
88
|
|
83
89
|
def message=(args)
|
84
|
-
|
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
|
+
|
85
101
|
interface(:message) do |int|
|
86
102
|
int.message = message.byteslice(0...MAX_MESSAGE_SIZE_IN_BYTES) # Messages limited to 10kb
|
87
103
|
int.params = params
|
@@ -159,7 +175,7 @@ module Raven
|
|
159
175
|
end
|
160
176
|
|
161
177
|
def stacktrace_interface_from(backtrace)
|
162
|
-
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|
|
163
179
|
frame = StacktraceInterface::Frame.new
|
164
180
|
frame.abs_path = line.file if line.file
|
165
181
|
frame.function = line.method if line.method
|
@@ -186,12 +202,6 @@ module Raven
|
|
186
202
|
|
187
203
|
private
|
188
204
|
|
189
|
-
def copy_initial_state
|
190
|
-
self.configuration = Raven.configuration
|
191
|
-
self.breadcrumbs = Raven.breadcrumbs
|
192
|
-
self.context = Raven.context
|
193
|
-
end
|
194
|
-
|
195
205
|
def set_core_attributes_from_configuration
|
196
206
|
self.server_name ||= configuration.server_name
|
197
207
|
self.release ||= configuration.release
|
@@ -216,6 +226,10 @@ module Raven
|
|
216
226
|
int.from_rack(context.rack_env)
|
217
227
|
end
|
218
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
|
219
233
|
end
|
220
234
|
|
221
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,6 +50,7 @@ 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
|
54
55
|
|
55
56
|
if configuration.capture_allowed?
|
@@ -76,7 +77,7 @@ module Raven
|
|
76
77
|
# Send an event to the configured Sentry server
|
77
78
|
#
|
78
79
|
# @example
|
79
|
-
# evt = Raven::Event.new(:message => "An
|
80
|
+
# evt = Raven::Event.new(:message => "An errore)
|
80
81
|
# Raven.send_event(evt)
|
81
82
|
def send_event(event, hint = nil)
|
82
83
|
client.send_event(event, hint)
|
@@ -110,8 +111,11 @@ module Raven
|
|
110
111
|
end
|
111
112
|
|
112
113
|
message_or_exc = obj.is_a?(String) ? "message" : "exception"
|
114
|
+
options = options.deep_dup
|
113
115
|
options[:configuration] = configuration
|
114
116
|
options[:context] = context
|
117
|
+
options[:breadcrumbs] = breadcrumbs
|
118
|
+
|
115
119
|
if evt = Event.send("from_" + message_or_exc, obj, options)
|
116
120
|
yield evt if block_given?
|
117
121
|
if configuration.async?
|
@@ -172,7 +176,18 @@ module Raven
|
|
172
176
|
# @example
|
173
177
|
# Raven.user_context('id' => 1, 'email' => 'foo@example.com')
|
174
178
|
def user_context(options = nil)
|
175
|
-
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?
|
176
191
|
end
|
177
192
|
|
178
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
|
@@ -29,7 +30,7 @@ module Delayed
|
|
29
30
|
extra[:handler] = job.handler[0...1000] if job.handler
|
30
31
|
|
31
32
|
if job.respond_to?('payload_object') && job.payload_object.respond_to?('job_data')
|
32
|
-
extra[:active_job] = job.payload_object.job_data
|
33
|
+
extra[:active_job] = ::Raven::Utils::ContextFilter.filter_context(job.payload_object.job_data)
|
33
34
|
end
|
34
35
|
::Raven.capture_exception(e,
|
35
36
|
:logger => 'delayed_job',
|
@@ -10,7 +10,11 @@ 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
|
|
@@ -100,7 +100,7 @@ module Raven
|
|
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,13 +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)
|
115
114
|
|
116
115
|
# Rack stores headers as HTTP_WHAT_EVER, we need What-Ever
|
117
116
|
key = key.sub(/^HTTP_/, "")
|
118
117
|
key = key.split('_').map(&:capitalize).join('-')
|
119
|
-
memo[key] = value
|
118
|
+
memo[key] = value.to_s
|
120
119
|
rescue StandardError => e
|
121
120
|
# Rails adds objects to the Rack env that can sometimes raise exceptions
|
122
121
|
# when `to_s` is called.
|
@@ -128,8 +127,10 @@ module Raven
|
|
128
127
|
end
|
129
128
|
|
130
129
|
def format_env_for_sentry(env_hash)
|
130
|
+
return env_hash if Raven.configuration.rack_env_whitelist.empty?
|
131
|
+
|
131
132
|
env_hash.select do |k, _v|
|
132
|
-
|
133
|
+
Raven.configuration.rack_env_whitelist.include? k.to_s
|
133
134
|
end
|
134
135
|
end
|
135
136
|
end
|
@@ -5,6 +5,7 @@ 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'
|
8
9
|
require 'raven/integrations/rack'
|
9
10
|
|
10
11
|
initializer "raven.use_rack_middleware" do |app|
|
@@ -37,12 +38,20 @@ module Raven
|
|
37
38
|
|
38
39
|
config.before_initialize do
|
39
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
|
40
47
|
end
|
41
48
|
|
42
49
|
config.after_initialize do
|
43
|
-
if Raven.configuration.
|
44
|
-
|
45
|
-
|
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
|
46
55
|
end
|
47
56
|
|
48
57
|
if Raven.configuration.rails_report_rescued_exceptions
|
@@ -21,7 +21,8 @@ module Raven
|
|
21
21
|
def capture_and_reraise_with_sentry(job, block)
|
22
22
|
block.call
|
23
23
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
24
|
-
|
24
|
+
rescue_handler_result = rescue_with_handler(e)
|
25
|
+
return rescue_handler_result if rescue_handler_result
|
25
26
|
|
26
27
|
Raven.capture_exception(e, :extra => raven_context(job))
|
27
28
|
raise e
|
@@ -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
|
@@ -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
|
@@ -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
|