sentry-raven 2.1.3 → 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.
Files changed (66) hide show
  1. checksums.yaml +5 -5
  2. data/.craft.yml +19 -0
  3. data/.scripts/bump-version.rb +5 -0
  4. data/CHANGELOG.md +703 -0
  5. data/Gemfile +37 -0
  6. data/Makefile +3 -0
  7. data/README.md +116 -18
  8. data/Rakefile +30 -0
  9. data/exe/raven +32 -0
  10. data/lib/raven/backtrace.rb +16 -6
  11. data/lib/raven/base.rb +17 -4
  12. data/lib/raven/breadcrumbs/{activesupport.rb → active_support_logger.rb} +9 -3
  13. data/lib/raven/breadcrumbs/logger.rb +2 -92
  14. data/lib/raven/breadcrumbs/sentry_logger.rb +73 -0
  15. data/lib/raven/breadcrumbs.rb +3 -1
  16. data/lib/raven/cli.rb +31 -43
  17. data/lib/raven/client.rb +39 -17
  18. data/lib/raven/configuration.rb +277 -37
  19. data/lib/raven/context.rb +17 -11
  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 +172 -233
  23. data/lib/raven/helpers/deprecation_helper.rb +17 -0
  24. data/lib/raven/instance.rb +51 -25
  25. data/lib/raven/integrations/delayed_job.rb +18 -18
  26. data/lib/raven/integrations/rack-timeout.rb +11 -5
  27. data/lib/raven/integrations/rack.rb +36 -19
  28. data/lib/raven/integrations/rails/active_job.rb +52 -20
  29. data/lib/raven/integrations/rails/backtrace_cleaner.rb +29 -0
  30. data/lib/raven/integrations/rails/controller_transaction.rb +13 -0
  31. data/lib/raven/integrations/rails/overrides/debug_exceptions_catcher.rb +2 -2
  32. data/lib/raven/integrations/rails.rb +24 -8
  33. data/lib/raven/integrations/rake.rb +6 -1
  34. data/lib/raven/integrations/sidekiq/cleanup_middleware.rb +13 -0
  35. data/lib/raven/integrations/sidekiq/error_handler.rb +38 -0
  36. data/lib/raven/integrations/sidekiq.rb +6 -57
  37. data/lib/raven/interface.rb +2 -2
  38. data/lib/raven/interfaces/exception.rb +0 -2
  39. data/lib/raven/interfaces/http.rb +0 -2
  40. data/lib/raven/interfaces/message.rb +1 -1
  41. data/lib/raven/interfaces/single_exception.rb +0 -2
  42. data/lib/raven/interfaces/stack_trace.rb +19 -27
  43. data/lib/raven/linecache.rb +34 -17
  44. data/lib/raven/logger.rb +11 -18
  45. data/lib/raven/processor/cookies.rb +27 -7
  46. data/lib/raven/processor/http_headers.rb +18 -5
  47. data/lib/raven/processor/post_data.rb +16 -3
  48. data/lib/raven/processor/removecircularreferences.rb +12 -8
  49. data/lib/raven/processor/removestacktrace.rb +17 -6
  50. data/lib/raven/processor/sanitizedata.rb +88 -29
  51. data/lib/raven/processor/utf8conversion.rb +39 -14
  52. data/lib/raven/processor.rb +1 -1
  53. data/lib/raven/transports/http.rb +29 -21
  54. data/lib/raven/transports/stdout.rb +20 -0
  55. data/lib/raven/transports.rb +4 -8
  56. data/lib/raven/utils/context_filter.rb +42 -0
  57. data/lib/raven/utils/deep_merge.rb +6 -12
  58. data/lib/raven/utils/exception_cause_chain.rb +20 -0
  59. data/lib/raven/utils/real_ip.rb +1 -1
  60. data/lib/raven/utils/request_id.rb +16 -0
  61. data/lib/raven/version.rb +2 -2
  62. data/lib/sentry-raven-without-integrations.rb +6 -1
  63. data/lib/sentry_raven_without_integrations.rb +1 -0
  64. data/sentry-raven.gemspec +28 -0
  65. metadata +37 -103
  66. data/lib/raven/error.rb +0 -4
@@ -19,16 +19,15 @@ module Raven
19
19
  # end
20
20
  # end
21
21
  class Instance
22
- # The client object is responsible for delivering formatted data to the
23
- # Sentry server. Must respond to #send. See Raven::Client.
22
+ # See Raven::Client.
24
23
  attr_writer :client
25
24
 
26
- # A Raven configuration object. Must act like a hash and return sensible
27
- # values for all Raven configuration options. See Raven::Configuration.
28
- attr_writer :configuration
25
+ # See Raven::Configuration.
26
+ attr_accessor :configuration
29
27
 
30
- def initialize(context = nil)
28
+ def initialize(context = nil, config = nil)
31
29
  @context = @explicit_context = context
30
+ self.configuration = config || Configuration.new
32
31
  end
33
32
 
34
33
  def context
@@ -40,13 +39,7 @@ module Raven
40
39
  end
41
40
 
42
41
  def logger
43
- @logger ||= Logger.new
44
- end
45
-
46
- # The configuration object.
47
- # @see Raven.configure
48
- def configuration
49
- @configuration ||= Configuration.new
42
+ configuration.logger
50
43
  end
51
44
 
52
45
  # The client object is responsible for delivering formatted data to the
@@ -57,11 +50,13 @@ module Raven
57
50
 
58
51
  # Tell the log that the client is good to go
59
52
  def report_status
53
+ return unless configuration.enabled_in_current_env?
60
54
  return if configuration.silence_ready
55
+
61
56
  if configuration.capture_allowed?
62
57
  logger.info "Raven #{VERSION} ready to catch errors"
63
58
  else
64
- logger.info "Raven #{VERSION} configured not to capture errors."
59
+ logger.info "Raven #{VERSION} configured not to capture errors: #{configuration.error_messages}"
65
60
  end
66
61
  end
67
62
 
@@ -82,10 +77,10 @@ module Raven
82
77
  # Send an event to the configured Sentry server
83
78
  #
84
79
  # @example
85
- # evt = Raven::Event.new(:message => "An error")
80
+ # evt = Raven::Event.new(:message => "An errore)
86
81
  # Raven.send_event(evt)
87
- def send_event(event)
88
- client.send_event(event)
82
+ def send_event(event, hint = nil)
83
+ client.send_event(event, hint)
89
84
  end
90
85
 
91
86
  # Capture and process any exceptions from the given block.
@@ -111,30 +106,38 @@ module Raven
111
106
 
112
107
  def capture_type(obj, options = {})
113
108
  unless configuration.capture_allowed?(obj)
114
- Raven.logger.debug("#{obj} excluded from capture due to environment or should_capture callback")
109
+ logger.debug("#{obj} excluded from capture: #{configuration.error_messages}")
115
110
  return false
116
111
  end
117
112
 
118
113
  message_or_exc = obj.is_a?(String) ? "message" : "exception"
119
- if (evt = Event.send("from_" + message_or_exc, obj, options))
114
+ options = options.deep_dup
115
+ options[:configuration] = configuration
116
+ options[:context] = context
117
+ options[:breadcrumbs] = breadcrumbs
118
+
119
+ if evt = Event.send("from_" + message_or_exc, obj, options)
120
120
  yield evt if block_given?
121
121
  if configuration.async?
122
122
  begin
123
123
  # We have to convert to a JSON-like hash, because background job
124
124
  # processors (esp ActiveJob) may not like weird types in the event hash
125
125
  configuration.async.call(evt.to_json_compatible)
126
- rescue => ex
127
- Raven.logger.error("async event sending failed: #{ex.message}")
128
- send_event(evt)
126
+ rescue => e
127
+ logger.error("async event sending failed: #{e.message}")
128
+ send_event(evt, make_hint(obj))
129
129
  end
130
130
  else
131
- send_event(evt)
131
+ send_event(evt, make_hint(obj))
132
132
  end
133
133
  Thread.current["sentry_#{object_id}_last_event_id".to_sym] = evt.id
134
134
  evt
135
135
  end
136
136
  end
137
137
 
138
+ alias capture_message capture_type
139
+ alias capture_exception capture_type
140
+
138
141
  def last_event_id
139
142
  Thread.current["sentry_#{object_id}_last_event_id".to_sym]
140
143
  end
@@ -160,7 +163,7 @@ module Raven
160
163
  # end
161
164
  def annotate_exception(exc, options = {})
162
165
  notes = (exc.instance_variable_defined?(:@__raven_context) && exc.instance_variable_get(:@__raven_context)) || {}
163
- notes.merge!(options)
166
+ Raven::Utils::DeepMergeHash.deep_merge!(notes, options)
164
167
  exc.instance_variable_set(:@__raven_context, notes)
165
168
  exc
166
169
  end
@@ -173,7 +176,18 @@ module Raven
173
176
  # @example
174
177
  # Raven.user_context('id' => 1, 'email' => 'foo@example.com')
175
178
  def user_context(options = nil)
176
- context.user = options || {}
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?
177
191
  end
178
192
 
179
193
  # Bind tags context. Merges with existing context (if any).
@@ -185,6 +199,10 @@ module Raven
185
199
  # Raven.tags_context('my_custom_tag' => 'tag_value')
186
200
  def tags_context(options = nil)
187
201
  context.tags.merge!(options || {})
202
+ yield if block_given?
203
+ context.tags
204
+ ensure
205
+ context.tags.delete_if { |k, _| options.keys.include? k } if block_given?
188
206
  end
189
207
 
190
208
  # Bind extra context. Merges with existing context (if any).
@@ -196,6 +214,10 @@ module Raven
196
214
  # Raven.extra_context('my_custom_data' => 'value')
197
215
  def extra_context(options = nil)
198
216
  context.extra.merge!(options || {})
217
+ yield if block_given?
218
+ context.extra
219
+ ensure
220
+ context.extra.delete_if { |k, _| options.keys.include? k } if block_given?
199
221
  end
200
222
 
201
223
  def rack_context(env)
@@ -219,5 +241,9 @@ module Raven
219
241
  end
220
242
  end
221
243
  end
244
+
245
+ def make_hint(obj)
246
+ obj.is_a?(String) ? { :exception => nil, :message => obj } : { :exception => obj, :message => nil }
247
+ end
222
248
  end
223
249
  end
@@ -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,40 +9,39 @@ 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 => job.id,
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
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
27
- extra[:last_error] = job.last_error[0...100] if job.last_error
27
+ extra[:last_error] = job.last_error[0...1000] if job.last_error
28
28
  # handlers are YAML objects in strings, we definitely can't
29
29
  # report all of that or the event will get truncated randomly
30
- extra[:handler] = job.handler[0...100] if job.handler
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(exception,
36
- :logger => 'delayed_job',
37
- :tags => {
35
+ ::Raven.capture_exception(e,
36
+ :logger => 'delayed_job',
37
+ :tags => {
38
38
  :delayed_job_queue => job.queue,
39
- :delayed_job_id => job.id
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 exception
44
+ raise e
45
45
  ensure
46
46
  ::Raven::Context.clear!
47
47
  ::Raven::BreadcrumbBuffer.clear!
@@ -1,6 +1,5 @@
1
- # rubocop:disable Style/FileName
2
1
  # We need to do this because of the way integration loading works
3
- require "rack/timeout/base"
2
+ require "rack/timeout/base" unless defined?(Rack::Timeout)
4
3
 
5
4
  # This integration is a good example of how to change how exceptions
6
5
  # get grouped by Sentry's UI. Simply override #raven_context in
@@ -8,9 +7,16 @@ require "rack/timeout/base"
8
7
  # that will distinguish exceptions in the way you desire.
9
8
  module RackTimeoutExtensions
10
9
  def raven_context
11
- { :fingerprint => ["{{ default }}", env["REQUEST_URI"]] }
10
+ # Only rack-timeout 0.3.0+ provides the request environment, but we can't
11
+ # gate this based on a gem version constant because rack-timeout does
12
+ # not provide one.
13
+ if defined?(env)
14
+ { :fingerprint => ["{{ default }}", env["REQUEST_URI"]] }
15
+ else
16
+ {}
17
+ end
12
18
  end
13
19
  end
14
20
 
15
- Rack::Timeout::Error.include RackTimeoutExtensions
16
- Rack::Timeout::RequestTimeoutException.include RackTimeoutExtensions
21
+ Rack::Timeout::Error.include(RackTimeoutExtensions)
22
+ Rack::Timeout::RequestTimeoutException.include(RackTimeoutExtensions)
@@ -45,6 +45,7 @@ module Raven
45
45
  # callers
46
46
  env['raven.requested_at'] = Time.now
47
47
  Raven.rack_context(env)
48
+ Raven.context.transaction.push(env["PATH_INFO"]) if env["PATH_INFO"]
48
49
 
49
50
  begin
50
51
  response = @app.call(env)
@@ -73,47 +74,63 @@ module Raven
73
74
  self.method = req.request_method
74
75
  self.query_string = req.query_string
75
76
  self.data = read_data_from(req)
77
+ self.cookies = req.cookies
76
78
 
77
79
  self.headers = format_headers_for_sentry(env_hash)
78
- self.env = format_env_for_sentry(env_hash)
80
+ self.env = format_env_for_sentry(env_hash)
79
81
  end
80
82
 
81
83
  private
82
84
 
85
+ # See Sentry server default limits at
86
+ # https://github.com/getsentry/sentry/blob/master/src/sentry/conf/server.py
83
87
  def read_data_from(request)
84
88
  if request.form_data?
85
89
  request.POST
86
90
  elsif request.body # JSON requests, etc
87
- data = request.body.read(2048) # Sentry server limit
91
+ data = request.body.read(4096 * 4) # Sentry server limit
88
92
  request.body.rewind
89
93
  data
90
94
  end
95
+ rescue IOError => e
96
+ e.message
91
97
  end
92
98
 
93
99
  def format_headers_for_sentry(env_hash)
94
100
  env_hash.each_with_object({}) do |(key, value), memo|
95
- key = key.to_s # rack env can contain symbols
96
- value = value.to_s
97
- next unless key.upcase == key # Non-upper case stuff isn't either
98
-
99
- # Rack adds in an incorrect HTTP_VERSION key, which causes downstream
100
- # to think this is a Version header. Instead, this is mapped to
101
- # env['SERVER_PROTOCOL']. But we don't want to ignore a valid header
102
- # if the request has legitimately sent a Version header themselves.
103
- # See: https://github.com/rack/rack/blob/028438f/lib/rack/handler/cgi.rb#L29
104
- next if key == 'HTTP_VERSION' && value == ENV['SERVER_PROTOCOL']
105
-
106
- next unless key.start_with?('HTTP_') || %w(CONTENT_TYPE CONTENT_LENGTH).include?(key)
107
- # Rack stores headers as HTTP_WHAT_EVER, we need What-Ever
108
- key = key.gsub("HTTP_", "")
109
- key = key.split('_').map(&:capitalize).join('-')
110
- memo[key] = value
101
+ begin
102
+ key = key.to_s # rack env can contain symbols
103
+ next memo['X-Request-Id'] ||= Utils::RequestId.read_from(env_hash) if Utils::RequestId::REQUEST_ID_HEADERS.include?(key)
104
+ next unless key.upcase == key # Non-upper case stuff isn't either
105
+
106
+ # Rack adds in an incorrect HTTP_VERSION key, which causes downstream
107
+ # to think this is a Version header. Instead, this is mapped to
108
+ # env['SERVER_PROTOCOL']. But we don't want to ignore a valid header
109
+ # if the request has legitimately sent a Version header themselves.
110
+ # See: https://github.com/rack/rack/blob/028438f/lib/rack/handler/cgi.rb#L29
111
+ next if key == 'HTTP_VERSION' && value == env_hash['SERVER_PROTOCOL']
112
+ next if key == 'HTTP_COOKIE' # Cookies don't go here, they go somewhere else
113
+ next unless key.start_with?('HTTP_') || %w(CONTENT_TYPE CONTENT_LENGTH).include?(key)
114
+
115
+ # Rack stores headers as HTTP_WHAT_EVER, we need What-Ever
116
+ key = key.sub(/^HTTP_/, "")
117
+ key = key.split('_').map(&:capitalize).join('-')
118
+ memo[key] = value.to_s
119
+ rescue StandardError => e
120
+ # Rails adds objects to the Rack env that can sometimes raise exceptions
121
+ # when `to_s` is called.
122
+ # See: https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/remote_ip.rb#L134
123
+ Raven.logger.warn("Error raised while formatting headers: #{e.message}")
124
+ next
125
+ end
111
126
  end
112
127
  end
113
128
 
114
129
  def format_env_for_sentry(env_hash)
130
+ return env_hash if Raven.configuration.rack_env_whitelist.empty?
131
+
115
132
  env_hash.select do |k, _v|
116
- %w(REMOTE_ADDR SERVER_NAME SERVER_PORT).include? k.to_s
133
+ Raven.configuration.rack_env_whitelist.include? k.to_s
117
134
  end
118
135
  end
119
136
  end
@@ -1,31 +1,63 @@
1
1
  module Raven
2
2
  class Rails
3
- module ActiveJob
3
+ module ActiveJobExtensions
4
+ ALREADY_SUPPORTED_SENTRY_ADAPTERS = %w(
5
+ ActiveJob::QueueAdapters::SidekiqAdapter
6
+ ActiveJob::QueueAdapters::DelayedJobAdapter
7
+ ).freeze
8
+
4
9
  def self.included(base)
5
10
  base.class_eval do
6
- rescue_from(Exception) do |exception|
7
- # Do not capture exceptions when using Sidekiq so we don't capture
8
- # The same exception twice.
9
- unless self.class.queue_adapter.to_s == 'ActiveJob::QueueAdapters::SidekiqAdapter'
10
- active_job_details = {
11
- :active_job => self.class.name,
12
- :arguments => arguments,
13
- :scheduled_at => scheduled_at,
14
- :job_id => job_id,
15
- :locale => locale
16
- }
17
-
18
- # Add provider_job_id details if Rails 5
19
- if defined?(provider_job_id)
20
- active_job_details[:provider_job_id] = provider_job_id
21
- end
22
-
23
- Raven.capture_exception(exception, :extra => active_job_details)
24
- raise exception
11
+ around_perform do |job, block|
12
+ if already_supported_by_specific_integration?(job)
13
+ block.call
14
+ else
15
+ capture_and_reraise_with_sentry(job, block)
25
16
  end
26
17
  end
27
18
  end
28
19
  end
20
+
21
+ def capture_and_reraise_with_sentry(job, block)
22
+ block.call
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
29
+ ensure
30
+ Context.clear!
31
+ BreadcrumbBuffer.clear!
32
+ end
33
+
34
+ def already_supported_by_specific_integration?(job)
35
+ if ::Rails.version.to_f < 5.0
36
+ ALREADY_SUPPORTED_SENTRY_ADAPTERS.include?(job.class.queue_adapter.to_s)
37
+ else
38
+ ALREADY_SUPPORTED_SENTRY_ADAPTERS.include?(job.class.queue_adapter.class.to_s)
39
+ end
40
+ end
41
+
42
+ def raven_context(job)
43
+ ctx = {
44
+ :active_job => job.class.name,
45
+ :arguments => job.arguments,
46
+ :scheduled_at => job.scheduled_at,
47
+ :job_id => job.job_id,
48
+ :locale => job.locale
49
+ }
50
+ # Add provider_job_id details if Rails 5
51
+ if job.respond_to?(:provider_job_id)
52
+ ctx[:provider_job_id] = job.provider_job_id
53
+ end
54
+
55
+ ctx
56
+ end
29
57
  end
30
58
  end
31
59
  end
60
+
61
+ class ActiveJob::Base
62
+ include Raven::Rails::ActiveJobExtensions
63
+ end
@@ -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
@@ -0,0 +1,13 @@
1
+ module Raven
2
+ class Rails
3
+ module ControllerTransaction
4
+ def self.included(base)
5
+ base.prepend_around_action do |controller, block|
6
+ Raven.context.transaction.push "#{controller.class}##{controller.action_name}"
7
+ block.call
8
+ Raven.context.transaction.pop
9
+ end
10
+ end
11
+ end
12
+ end
13
+ 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 # rubocop:disable Lint/HandleExceptions
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 # rubocop:disable Lint/HandleExceptions
24
+ rescue
25
25
  end
26
26
  render_exception_without_raven(env_or_request, exception)
27
27
  end
@@ -4,6 +4,9 @@ module Raven
4
4
  class Rails < ::Rails::Railtie
5
5
  require 'raven/integrations/rails/overrides/streaming_reporter'
6
6
  require 'raven/integrations/rails/controller_methods'
7
+ require 'raven/integrations/rails/controller_transaction'
8
+ require 'raven/integrations/rails/backtrace_cleaner'
9
+ require 'raven/integrations/rack'
7
10
 
8
11
  initializer "raven.use_rack_middleware" do |app|
9
12
  app.config.middleware.insert 0, Raven::Rack
@@ -12,6 +15,7 @@ module Raven
12
15
  initializer 'raven.action_controller' do
13
16
  ActiveSupport.on_load :action_controller do
14
17
  include Raven::Rails::ControllerMethods
18
+ include Raven::Rails::ControllerTransaction
15
19
  if ::Rails::VERSION::STRING >= "4.0.0"
16
20
  Raven.safely_prepend(
17
21
  "StreamingReporter",
@@ -32,16 +36,22 @@ module Raven
32
36
  end
33
37
  end
34
38
 
35
- config.after_initialize do
36
- Raven.configure do |config|
37
- config.logger ||= ::Rails.logger
38
- config.project_root ||= ::Rails.root
39
- config.release ||= config.detect_release # if project_root has changed, need to re-check
39
+ config.before_initialize do
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)
40
46
  end
47
+ end
41
48
 
42
- if Raven.configuration.rails_activesupport_breadcrumbs
43
- require 'raven/breadcrumbs/activesupport'
44
- Raven::ActiveSupportBreadcrumbs.inject
49
+ config.after_initialize do
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
@@ -60,6 +70,12 @@ module Raven
60
70
  end
61
71
  end
62
72
 
73
+ initializer 'raven.active_job' do
74
+ ActiveSupport.on_load :active_job do
75
+ require 'raven/integrations/rails/active_job'
76
+ end
77
+ end
78
+
63
79
  rake_tasks do
64
80
  require 'raven/integrations/tasks'
65
81
  end
@@ -6,7 +6,12 @@ module Rake
6
6
  class Application
7
7
  alias orig_display_error_messsage display_error_message
8
8
  def display_error_message(ex)
9
- Raven.capture_exception ex, :logger => 'rake', :tags => { 'rake_task' => @name }
9
+ Raven.capture_exception(
10
+ ex,
11
+ :transaction => top_level_tasks.join(' '),
12
+ :logger => 'rake',
13
+ :tags => { 'rake_task' => top_level_tasks.join(' ') }
14
+ )
10
15
  orig_display_error_messsage(ex)
11
16
  end
12
17
  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