sentry-raven 3.0.2 → 3.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|