sentry-raven 3.0.4 → 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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/.craft.yml +9 -5
  3. data/.scripts/bump-version.rb +5 -0
  4. data/CHANGELOG.md +145 -1
  5. data/Gemfile +5 -1
  6. data/Makefile +3 -0
  7. data/README.md +26 -8
  8. data/lib/raven/backtrace.rb +2 -0
  9. data/lib/raven/base.rb +2 -0
  10. data/lib/raven/breadcrumbs/active_support_logger.rb +25 -0
  11. data/lib/raven/breadcrumbs/logger.rb +2 -92
  12. data/lib/raven/breadcrumbs/sentry_logger.rb +73 -0
  13. data/lib/raven/cli.rb +1 -1
  14. data/lib/raven/client.rb +1 -1
  15. data/lib/raven/configuration.rb +75 -4
  16. data/lib/raven/context.rb +13 -8
  17. data/lib/raven/event.rb +27 -13
  18. data/lib/raven/helpers/deprecation_helper.rb +17 -0
  19. data/lib/raven/instance.rb +15 -2
  20. data/lib/raven/integrations/delayed_job.rb +2 -1
  21. data/lib/raven/integrations/rack-timeout.rb +5 -1
  22. data/lib/raven/integrations/rack.rb +5 -4
  23. data/lib/raven/integrations/rails.rb +12 -3
  24. data/lib/raven/integrations/rails/active_job.rb +2 -1
  25. data/lib/raven/integrations/rails/backtrace_cleaner.rb +29 -0
  26. data/lib/raven/integrations/sidekiq.rb +4 -78
  27. data/lib/raven/integrations/sidekiq/cleanup_middleware.rb +13 -0
  28. data/lib/raven/integrations/sidekiq/error_handler.rb +38 -0
  29. data/lib/raven/transports/http.rb +2 -3
  30. data/lib/raven/utils/context_filter.rb +42 -0
  31. data/lib/raven/utils/request_id.rb +16 -0
  32. data/lib/raven/version.rb +1 -1
  33. data/lib/sentry-raven-without-integrations.rb +6 -1
  34. data/lib/sentry_raven_without_integrations.rb +1 -0
  35. data/sentry-raven.gemspec +7 -0
  36. metadata +18 -12
  37. data/.github/workflows/test.yml +0 -87
  38. data/.github/workflows/zeus_upload.yml +0 -32
  39. data/.gitignore +0 -15
  40. data/.gitmodules +0 -0
  41. data/.rspec +0 -1
  42. data/.rubocop.yml +0 -109
  43. data/.scripts/bump-version.sh +0 -9
  44. data/CONTRIUTING.md +0 -26
  45. data/lib/raven/breadcrumbs/activesupport.rb +0 -19
@@ -0,0 +1,73 @@
1
+ require 'logger'
2
+
3
+ module Raven
4
+ module Breadcrumbs
5
+ module SentryLogger
6
+ LEVELS = {
7
+ ::Logger::DEBUG => 'debug',
8
+ ::Logger::INFO => 'info',
9
+ ::Logger::WARN => 'warn',
10
+ ::Logger::ERROR => 'error',
11
+ ::Logger::FATAL => 'fatal'
12
+ }.freeze
13
+
14
+ def add(*args)
15
+ add_breadcrumb(*args)
16
+ super
17
+ end
18
+
19
+ def add_breadcrumb(severity, message = nil, progname = nil)
20
+ message = progname if message.nil? # see Ruby's Logger docs for why
21
+ return if ignored_logger?(progname)
22
+ return if message.nil? || message == ""
23
+
24
+ # some loggers will add leading/trailing space as they (incorrectly, mind you)
25
+ # think of logging as a shortcut to std{out,err}
26
+ message = message.to_s.strip
27
+
28
+ last_crumb = Raven.breadcrumbs.peek
29
+ # try to avoid dupes from logger broadcasts
30
+ if last_crumb.nil? || last_crumb.message != message
31
+ Raven.breadcrumbs.record do |crumb|
32
+ crumb.level = Raven::Breadcrumbs::SentryLogger::LEVELS.fetch(severity, nil)
33
+ crumb.category = progname || 'logger'
34
+ crumb.message = message
35
+ crumb.type =
36
+ if severity >= 3
37
+ "error"
38
+ else
39
+ crumb.level
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def ignored_logger?(progname)
48
+ progname == "sentry" ||
49
+ Raven.configuration.exclude_loggers.include?(progname)
50
+ end
51
+ end
52
+ module OldBreadcrumbsSentryLogger
53
+ def self.included(base)
54
+ base.class_eval do
55
+ include Raven::Breadcrumbs::SentryLogger
56
+ alias_method :add_without_raven, :add
57
+ alias_method :add, :add_with_raven
58
+ end
59
+ end
60
+
61
+ def add_with_raven(*args)
62
+ add_breadcrumb(*args)
63
+ add_without_raven(*args)
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ Raven.safely_prepend(
70
+ "Breadcrumbs::SentryLogger",
71
+ :from => Raven,
72
+ :to => ::Logger
73
+ )
data/lib/raven/cli.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Raven
2
2
  class CLI
3
- def self.test(dsn = nil, silent = false, config = nil) # rubocop:disable all
3
+ def self.test(dsn = nil, silent = false, config = nil)
4
4
  config ||= Raven.configuration
5
5
 
6
6
  config.logger = if silent
data/lib/raven/client.rb CHANGED
@@ -125,7 +125,7 @@ module Raven
125
125
  configuration.logger.warn("Failed to submit event: #{get_log_message(event)}")
126
126
 
127
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
128
+ configuration.transport_failure_callback.call(event, e) if configuration.transport_failure_callback # rubocop:disable Style/SafeNavigation
129
129
  end
130
130
  end
131
131
 
@@ -12,6 +12,11 @@ module Raven
12
12
  attr_reader :async
13
13
  alias async? async
14
14
 
15
+ # An array of breadcrumbs loggers to be used. Available options are:
16
+ # - :sentry_logger
17
+ # - :active_support_logger
18
+ attr_reader :breadcrumbs_logger
19
+
15
20
  # Number of lines of code context to capture, or nil for none
16
21
  attr_accessor :context_lines
17
22
 
@@ -83,7 +88,7 @@ module Raven
83
88
  attr_accessor :public_key
84
89
 
85
90
  # Turns on ActiveSupport breadcrumbs integration
86
- attr_accessor :rails_activesupport_breadcrumbs
91
+ attr_reader :rails_activesupport_breadcrumbs
87
92
 
88
93
  # Rails catches exceptions in the ActionDispatch::ShowExceptions or
89
94
  # ActionDispatch::DebugExceptions middlewares, depending on the environment.
@@ -118,6 +123,19 @@ module Raven
118
123
  # Otherwise, can be one of "http", "https", or "dummy"
119
124
  attr_accessor :scheme
120
125
 
126
+ # a proc/lambda that takes an array of stack traces
127
+ # it'll be used to silence (reduce) backtrace of the exception
128
+ #
129
+ # for example:
130
+ #
131
+ # ```ruby
132
+ # Raven.configuration.backtrace_cleanup_callback = lambda do |backtrace|
133
+ # Rails.backtrace_cleaner.clean(backtrace)
134
+ # end
135
+ # ```
136
+ #
137
+ attr_accessor :backtrace_cleanup_callback
138
+
121
139
  # Secret key for authentication with the Sentry server
122
140
  # If you provide a DSN, this will be set automatically.
123
141
  #
@@ -172,16 +190,34 @@ module Raven
172
190
  # Errors object - an Array that contains error messages. See #
173
191
  attr_reader :errors
174
192
 
193
+ # the dsn value, whether it's set via `config.dsn=` or `ENV["SENTRY_DSN"]`
194
+ attr_reader :dsn
195
+
196
+ # Array of rack env parameters to be included in the event sent to sentry.
197
+ attr_accessor :rack_env_whitelist
198
+
199
+ # Most of these errors generate 4XX responses. In general, Sentry clients
200
+ # only automatically report 5xx responses.
175
201
  IGNORE_DEFAULT = [
176
202
  'AbstractController::ActionNotFound',
203
+ 'ActionController::BadRequest',
177
204
  'ActionController::InvalidAuthenticityToken',
205
+ 'ActionController::InvalidCrossOriginRequest',
206
+ 'ActionController::MethodNotAllowed',
207
+ 'ActionController::NotImplemented',
208
+ 'ActionController::ParameterMissing',
178
209
  'ActionController::RoutingError',
179
210
  'ActionController::UnknownAction',
211
+ 'ActionController::UnknownFormat',
212
+ 'ActionController::UnknownHttpMethod',
213
+ 'ActionDispatch::Http::Parameters::ParseError',
214
+ 'ActiveJob::DeserializationError', # Can cause infinite loops
180
215
  'ActiveRecord::RecordNotFound',
181
216
  'CGI::Session::CookieStore::TamperedWithCookie',
182
217
  'Mongoid::Errors::DocumentNotFound',
183
- 'Sinatra::NotFound',
184
- 'ActiveJob::DeserializationError'
218
+ 'Rack::QueryParser::InvalidParameterError',
219
+ 'Rack::QueryParser::ParameterTypeError',
220
+ 'Sinatra::NotFound'
185
221
  ].freeze
186
222
 
187
223
  # Note the order - we have to remove circular references and bad characters
@@ -198,11 +234,20 @@ module Raven
198
234
  HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
199
235
  "release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`".freeze
200
236
 
237
+ RACK_ENV_WHITELIST_DEFAULT = %w(
238
+ REMOTE_ADDR
239
+ SERVER_NAME
240
+ SERVER_PORT
241
+ ).freeze
242
+
201
243
  LOG_PREFIX = "** [Raven] ".freeze
202
244
  MODULE_SEPARATOR = "::".freeze
203
245
 
246
+ AVAILABLE_BREADCRUMBS_LOGGERS = [:sentry_logger, :active_support_logger].freeze
247
+
204
248
  def initialize
205
249
  self.async = false
250
+ self.breadcrumbs_logger = []
206
251
  self.context_lines = 3
207
252
  self.current_environment = current_environment_from_env
208
253
  self.encoding = 'gzip'
@@ -215,7 +260,8 @@ module Raven
215
260
  self.open_timeout = 1
216
261
  self.processors = DEFAULT_PROCESSORS.dup
217
262
  self.project_root = detect_project_root
218
- self.rails_activesupport_breadcrumbs = false
263
+ @rails_activesupport_breadcrumbs = false
264
+
219
265
  self.rails_report_rescued_exceptions = true
220
266
  self.release = detect_release
221
267
  self.sample_rate = 1.0
@@ -232,11 +278,14 @@ module Raven
232
278
  self.timeout = 2
233
279
  self.transport_failure_callback = false
234
280
  self.before_send = false
281
+ self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
235
282
  end
236
283
 
237
284
  def server=(value)
238
285
  return if value.nil?
239
286
 
287
+ @dsn = value
288
+
240
289
  uri = URI.parse(value)
241
290
  uri_path = uri.path.split('/')
242
291
 
@@ -273,6 +322,23 @@ module Raven
273
322
  @async = value
274
323
  end
275
324
 
325
+ def breadcrumbs_logger=(logger)
326
+ loggers =
327
+ if logger.is_a?(Array)
328
+ logger
329
+ else
330
+ unless AVAILABLE_BREADCRUMBS_LOGGERS.include?(logger)
331
+ raise Raven::Error, "Unsupported breadcrumbs logger. Supported loggers: #{AVAILABLE_BREADCRUMBS_LOGGERS}"
332
+ end
333
+
334
+ Array(logger)
335
+ end
336
+
337
+ require "raven/breadcrumbs/sentry_logger" if loggers.include?(:sentry_logger)
338
+
339
+ @breadcrumbs_logger = logger
340
+ end
341
+
276
342
  def transport_failure_callback=(value)
277
343
  unless value == false || value.respond_to?(:call)
278
344
  raise(ArgumentError, "transport_failure_callback must be callable (or false to disable)")
@@ -329,6 +395,11 @@ module Raven
329
395
  Backtrace::Line.instance_variable_set(:@in_app_pattern, nil) # blow away cache
330
396
  end
331
397
 
398
+ def rails_activesupport_breadcrumbs=(val)
399
+ DeprecationHelper.deprecate_old_breadcrumbs_configuration(:active_support_logger)
400
+ @rails_activesupport_breadcrumbs = val
401
+ end
402
+
332
403
  def exception_class_allowed?(exc)
333
404
  if exc.is_a?(Raven::Error)
334
405
  # Try to prevent error reporting loops
data/lib/raven/context.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'rbconfig'
2
+ require 'etc'
2
3
 
3
4
  module Raven
4
5
  class Context
@@ -24,18 +25,22 @@ module Raven
24
25
 
25
26
  class << self
26
27
  def os_context
27
- @os_context ||= {
28
- :name => Raven.sys_command("uname -s") || RbConfig::CONFIG["host_os"],
29
- :version => Raven.sys_command("uname -v"),
30
- :build => Raven.sys_command("uname -r"),
31
- :kernel_version => Raven.sys_command("uname -a") || Raven.sys_command("ver") # windows
32
- }
28
+ @os_context ||=
29
+ begin
30
+ uname = Etc.uname
31
+ {
32
+ name: uname[:sysname] || RbConfig::CONFIG["host_os"],
33
+ version: uname[:version],
34
+ build: uname[:release],
35
+ kernel_version: uname[:version]
36
+ }
37
+ end
33
38
  end
34
39
 
35
40
  def runtime_context
36
41
  @runtime_context ||= {
37
- :name => RbConfig::CONFIG["ruby_install_name"],
38
- :version => Raven.sys_command("ruby -v")
42
+ name: RbConfig::CONFIG["ruby_install_name"],
43
+ version: RUBY_DESCRIPTION || Raven.sys_command("ruby -v")
39
44
  }
40
45
  end
41
46
  end
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(init = {})
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
- copy_initial_state
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
- init.each_pair { |key, val| public_send("#{key}=", val) unless val.nil? }
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
- configuration = options[:configuration] || Raven.configuration
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
- message, params = *args
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
@@ -77,7 +77,7 @@ module Raven
77
77
  # Send an event to the configured Sentry server
78
78
  #
79
79
  # @example
80
- # evt = Raven::Event.new(:message => "An error")
80
+ # evt = Raven::Event.new(:message => "An errore)
81
81
  # Raven.send_event(evt)
82
82
  def send_event(event, hint = nil)
83
83
  client.send_event(event, hint)
@@ -114,6 +114,8 @@ module Raven
114
114
  options = options.deep_dup
115
115
  options[:configuration] = configuration
116
116
  options[:context] = context
117
+ options[:breadcrumbs] = breadcrumbs
118
+
117
119
  if evt = Event.send("from_" + message_or_exc, obj, options)
118
120
  yield evt if block_given?
119
121
  if configuration.async?
@@ -174,7 +176,18 @@ module Raven
174
176
  # @example
175
177
  # Raven.user_context('id' => 1, 'email' => 'foo@example.com')
176
178
  def user_context(options = nil)
177
- 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?
178
191
  end
179
192
 
180
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',