sentry-raven 2.6.3 → 2.7.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 29f898ece848c6fd9bf471b62dbfb990c41f30a1
4
- data.tar.gz: d290053185690206a198fb29ace1e6443534be7b
3
+ metadata.gz: 720bbe2b86e0c01584514a17c2f6299bb1313af1
4
+ data.tar.gz: 0410c196dffd1e8d0617ff1d01335c120b9dfa3c
5
5
  SHA512:
6
- metadata.gz: 7eb80ee3da6a36d2e8304dfcbf8f5d339340d401543d4c8fd9ae9340c923e49a889e6d0266c55bbc316183c882b595fba05c52e8422c560d36d4a2c2f049784a
7
- data.tar.gz: a4489464ff92761b746fd3b6be2ef384eb06a2d365ccf6e386e5feb46ca25fcb92ed8e4970e9aef5e684cf4b56d61f83ea6ca8dbacf344ece036227c0145425e
6
+ metadata.gz: 81eb505ebd43d3946a29ecd8e73ea67349c64907eee5821e1259e36353b6b204c7a42c7b584a4f2e93b1d45ee4a5fddf43c7c1f8315f5e63ff123caad2f73656
7
+ data.tar.gz: f81baee39e752d97874a88f6c37457325d0ab3baa9a8d3b54a495842bf08095879940854965023cda72397d85ee00e8839b51c6bd7954a0c8668143df57c0c2f
data/.rspec CHANGED
@@ -1,2 +1 @@
1
1
  --colour
2
- --format documentation
@@ -7,7 +7,7 @@ AllCops:
7
7
  - 'vendor/**/*'
8
8
 
9
9
  Metrics/ClassLength:
10
- Max: 248
10
+ Max: 262
11
11
  CountComments: false
12
12
 
13
13
  Metrics/AbcSize:
@@ -8,9 +8,9 @@ branches:
8
8
  only: [master]
9
9
 
10
10
  rvm:
11
- - 2.2.7
12
- - 2.3.4
13
- - 2.4.1
11
+ - 2.2.8
12
+ - 2.3.5
13
+ - 2.4.2
14
14
 
15
15
  env:
16
16
  - RAILS_VERSION=4
@@ -24,6 +24,7 @@ addons:
24
24
 
25
25
  before_install:
26
26
  - service haveged start
27
+ - gem install bundler
27
28
 
28
29
  matrix:
29
30
  include:
@@ -31,9 +32,9 @@ matrix:
31
32
  env: RAILS_VERSION=4
32
33
  - rvm: jruby-1.7.27
33
34
  env: JRUBY_OPTS="--dev" RAILS_VERSION=4
34
- - rvm: jruby-9.1.12.0
35
+ - rvm: jruby-9.1.13.0
35
36
  env: JRUBY_OPTS="--dev -J-Djruby.launch.inproc=true -J-Xmx1024M" RAILS_VERSION=4
36
- - rvm: jruby-9.1.12.0
37
+ - rvm: jruby-9.1.13.0
37
38
  env: JRUBY_OPTS="--dev -J-Djruby.launch.inproc=true -J-Xmx1024M" RAILS_VERSION=5
38
39
  - rvm: ruby-head
39
40
  env: RAILS_VERSION=0
data/README.md CHANGED
@@ -89,9 +89,6 @@ config.async = lambda { |event| SentryJob.perform_later(event) }
89
89
  class SentryJob < ActiveJob::Base
90
90
  queue_as :default
91
91
 
92
- # Important for ActiveJob! Otherwise, we can get caught in an infinite loop.
93
- rescue_from(ActiveJob::DeserializationError) { |e| Rails.logger.error e }
94
-
95
92
  def perform(event)
96
93
  Raven.send_event(event)
97
94
  end
@@ -1,3 +1,25 @@
1
+ 2.7.1
2
+ -----
3
+
4
+ * BUGFIX: Fixed LocalJumpError in Rails controllers [@nateberkopec w/@frodsan, #774]
5
+
6
+ 2.7.0
7
+ -----
8
+
9
+ * FEATURE: Add random sampling. [@nateberkopec, #734]
10
+ * FEATURE: Transactions. See Context docs for usage. [@nateberkopec, #743]
11
+ * FEATURE: You can set the current environment for Sentry via `SENTRY_CURRENT_ENV` env variable. Useful if your staging environment's RACK_ENV is "production", for example. [@tijmenb, #736]
12
+
13
+ * BUGFIX: Fix wrapped classnames in old versions of Sidekiq and ActiveJob [@nateberkopec, #702]
14
+ * BUGFIX: Server names on Heroku were pretty useless before - now they follow the dyno name ("worker.1", "web.2") [@nateberkopec, #703]
15
+ * BUGFIX: ActiveJob::DeserializationError is now ignored by default. Not doing so can cause infinite loops if you are using an ActiveJob async callback. [@nateberkopec, #701]
16
+ * BUGFIX: Binary conversion to UTF-8 when binary is frozen is fixed [@nateberkopec, #757]
17
+ * BUGFIX: Our credit-card regex now matches Sentry's server behavior, which means it does not censor milliseconds since the epoch [@nateberkopec, #771]
18
+
19
+ * REFACTOR: We now use an updated port of Rails' deep_merge which should be 5-10% faster [@nateberkopec, #770]
20
+ * REFACTOR: Tests have been cleaned up, and now run in random order. [@nateberkopec]
21
+ * REFACTOR: Raven::Event has been refactored a bit [@nateberkopec]
22
+
1
23
  2.6.3
2
24
  -----
3
25
 
@@ -1,3 +1,5 @@
1
+ .. versionadded:: 1.2
2
+
1
3
  Breadcrumbs
2
4
  ===========
3
5
 
@@ -38,3 +40,12 @@ Appropriate places to inject Breadcrumbs may be places like your HTTP library:
38
40
  end
39
41
  end
40
42
  end
43
+
44
+ .. versionadded:: 2.6
45
+
46
+ The breadcrumb buffer is publicly accessible if you wish to manipulate it beyond
47
+ what is possible with the ``record`` method.
48
+
49
+ .. sourcecode:: ruby
50
+
51
+ Raven.breadcrumbs.buffer # Array of breadcrumbs
@@ -23,7 +23,12 @@ Optional settings
23
23
  Thread.new { Raven.send_event(event) }
24
24
  }
25
25
 
26
- Using a thread to send events will be adequate for truly parallel Ruby platforms such as JRuby, though the benefit on MRI/CRuby will be limited. Threads also won't report any exceptions raised inside of them, so be careful!
26
+ Using a thread to send events will be adequate for truly parallel Ruby platforms such as JRuby, though the benefit on MRI/CRuby will be limited.
27
+
28
+ The example above is extremely basic. For example, exceptions in Rake tasks
29
+ will not be reported because the Rake task will probably exit before the thread
30
+ can completely send the event to Sentry. Threads also won't report any
31
+ exceptions raised inside of them, so be careful!
27
32
 
28
33
  If the async callback raises an exception, Raven will attempt to send synchronously.
29
34
 
@@ -40,9 +45,6 @@ Optional settings
40
45
  class SentryJob < ActiveJob::Base
41
46
  queue_as :default
42
47
 
43
- # Important! Otherwise, we can get caught in an infinite loop.
44
- rescue_from(ActiveJob::DeserializationError) { |e| Rails.logger.error e }
45
-
46
48
  def perform(event)
47
49
  Raven.send_event(event)
48
50
  end
@@ -68,7 +70,7 @@ Optional settings
68
70
 
69
71
  config.environments = %w[ production ]
70
72
 
71
- Sentry automatically sets the current environment to RAILS_ENV, or if it is not present, RACK_ENV. If you are using Sentry outside of Rack or Rails, or wish to override environment detection, you'll need to set the current environment yourself:
73
+ Sentry automatically sets the current environment to RAILS_ENV, or if it is not present, RACK_ENV. If you are using Sentry outside of Rack or Rails, or wish to override environment detection, you'll need to set the current environment by setting SENTRY_CURRENT_ENV or configuring the client yourself:
72
74
 
73
75
  .. code-block:: ruby
74
76
 
@@ -183,6 +185,16 @@ Optional settings
183
185
 
184
186
  config.release = '721e41770371db95eee98ca2707686226b993eda'
185
187
 
188
+ .. describe:: sample_rate
189
+
190
+ The sampling factor to apply to events. A value of 0.00 will deny sending
191
+ any events, and a value of 1.00 will send 100% of events.
192
+
193
+ .. code-block:: ruby
194
+
195
+ # send 50% of events
196
+ config.sample_rate = 0.5
197
+
186
198
  .. describe:: should_capture
187
199
 
188
200
  By providing a proc or lambda, you can control what events are captured. Events are passed to the Proc or lambda you provide - returning false will stop the event from sending to Sentry:
@@ -25,6 +25,7 @@ The following attributes are available:
25
25
  * ``tags``: a mapping of tags describing this event
26
26
  * ``extra``: a mapping of arbitrary context
27
27
  * ``user``: a mapping of user context
28
+ * ``transaction``: An array of strings. The final element in the array represents the current transaction, e.g. "HelloController#hello_world" for a Rails controller.
28
29
 
29
30
  Providing Request Context
30
31
  -------------------------
@@ -116,3 +117,25 @@ for you, otherwise you'll need to ensure you perform it manually:
116
117
 
117
118
  Note: the rack and user context will perform a set operation, whereas tags
118
119
  and extra context will merge with any existing request context.
120
+
121
+ Transactions
122
+ ~~~~~~~~~~~~
123
+
124
+ The "transaction" is intended to represent the action the event occurred during.
125
+ In Rack, this will be the request URL. In Rails, it's the controller name and
126
+ action ("HelloController#hello_world").
127
+
128
+ Transactions are modeled as a stack. The top item in the stack (i.e. the last
129
+ element of the array) will be used as the ``transaction`` for any events:
130
+
131
+ .. sourcecode:: ruby
132
+
133
+ Raven.context.transactions.push "User Import"
134
+ # import some users
135
+ Raven.context.transactions.pop
136
+
137
+ Transactions may also be overridden/set explicitly during event creation:
138
+
139
+ .. sourcecode:: ruby
140
+
141
+ Raven.capture_exception(exception, transaction: "User Import")
@@ -104,6 +104,7 @@ the library and the client integrations.
104
104
 
105
105
  breadcrumbs
106
106
  context
107
+ processors
107
108
  integrations/index
108
109
 
109
110
  Resources:
@@ -23,7 +23,7 @@ Puma provides a config option for handling low level errors.
23
23
  ex,
24
24
  :message => ex.message,
25
25
  :extra => { :puma => env },
26
- :culprit => "Puma"
26
+ :transaction => "Puma"
27
27
  )
28
28
  # note the below is just a Rack response
29
29
  [500, {}, ["An error has occurred, and engineers have been informed. Please reload the page. If you continue to have problems, contact support@example.com\n"]]
@@ -0,0 +1,124 @@
1
+ Processors
2
+ ==========
3
+
4
+ Raven Ruby contains several "processors", which scrub data before it is sent to Sentry.
5
+ Processors remove invalid or sensitive data. The following are the processors
6
+ which are enabled by default (and are applied to all outgoing data in this order):
7
+
8
+ RemoveCircularReferences
9
+ Many Ruby JSON implementations simply throw an exception if they detect a
10
+ circular reference. This processor removes circular references from hashes
11
+ and arrays.
12
+
13
+ UTF8Conversion
14
+ Many Ruby JSON implementations will throw exceptions if data is not in a
15
+ consistent UTF-8 format. This processor looks for invalid encodings and fixes
16
+ them.
17
+
18
+ SanitizeData
19
+ Censors any data which looks like a password, social security number or credit
20
+ card number. Can be configured to scrub other data.
21
+
22
+ Cookies
23
+ Removes any HTTP cookies from the Sentry event data.
24
+
25
+ PostData
26
+ Removes any HTTP Post request bodies.
27
+
28
+ HTTPHeaders
29
+ Removes all HTTP headers which match a regex. By default, this will only remove the
30
+ "Authorization" header, but can be configured to remove others.
31
+
32
+ Finally, another processor is included in the source but is not turned on by default,
33
+ RemoveStackTrace.
34
+
35
+ To remove stacktraces from events:
36
+
37
+ .. sourcecode:: ruby
38
+
39
+ Raven.configure do |config|
40
+ config.processors += [Raven::Processor::RemoveStacktrace]
41
+ end
42
+
43
+ Writing Your Own Processor
44
+ --------------------------
45
+
46
+ Processors are simple to write and understand. As an example, let's say that we
47
+ send user API keys to a background job (using Sidekiq), and if the background job
48
+ raises an exception, we want to make sure that the API key is removed from the
49
+ event data.
50
+
51
+ This is what a basic processor might look like:
52
+
53
+ .. sourcecode:: ruby
54
+
55
+ class MyJobProcessor < Raven::Processor
56
+ def process(data)
57
+ return data unless data["extra"]["arguments"] &&
58
+ data["extra"]["arguments"].first["sensitive_parameter"]
59
+
60
+ data["extra"]["arguments"].first["sensitive_parameter"] = STRING_MASK
61
+ data
62
+ end
63
+ end
64
+
65
+ Processors should inherit from the ``Raven::Processor`` class. This ensures that the
66
+ processor has access to its client (all processors have a ``client`` instance method,
67
+ which will be populated with the current ``Raven::Client`` when the processor
68
+ is initialized), and gives you a few convenient constants for masking data.
69
+
70
+ Processors must have a method called ``process`` defined. It must accept one
71
+ argument, which will be the Raven event data hash. The method must return a hash,
72
+ which represents the data after it has been modified by the processor.
73
+
74
+ To help you in writing your own processor, here is what the Event data hash looks
75
+ like (slightly modified/concatenated) when it is passed to the processor:
76
+
77
+ .. sourcecode:: ruby
78
+
79
+ {
80
+ "environment" => "default",
81
+ "event_id" => "02ea6d3d35c840b1a8f339ba896917e3",
82
+ "extra" => {
83
+ "server" => {
84
+ # server related information
85
+ }
86
+ "active_job" => "MyActiveJob",
87
+ "arguments" => [ {"sensitive_parameter": "sensitive"} ],
88
+ "job_id" => "cbc2c146-0486-4e98-b81c-1a251d636b34",
89
+ },
90
+ "modules" => {
91
+ "rake"=>"12.0.0",
92
+ "concurrent-ruby"=>"1.0.5",
93
+ "i18n"=>"0.8.6",
94
+ "minitest"=>"5.10.3",
95
+ # ...
96
+ },
97
+ "platform" => "ruby",
98
+ "release" => "e4d5ced",
99
+ "sdk" => {"name"=>"raven-ruby", "version"=>"2.6.3"},
100
+ "server_name" => "myserver.local",
101
+ "timestamp" => "2017-10-09T19:53:20",
102
+ "exception" => {
103
+ # A very large and complex exception object
104
+ }
105
+ }
106
+
107
+ However, it will probably be more helpful if you use a debugger, such as `pry`, to
108
+ inspect the event data hash for yourself.
109
+
110
+ The example processor given above looks for the ActiveJob arguments hash, looks for
111
+ a particular value, and then replaces it with the string mask. There is a fast return
112
+ if the event does not contain the ActiveJob data we're looking for, using Ruby 2.3+'s
113
+ safe navigation operator.
114
+
115
+ Once you have your processor written, you simply need to add it to the processor chain:
116
+
117
+ .. sourcecode:: ruby
118
+
119
+ Raven.configure do |config|
120
+ config.processors += MyJobProcessor
121
+ end
122
+
123
+ For more information about writing processors, read the code for the default
124
+ processors, located in ``lib/processor``.
@@ -5,6 +5,7 @@ module Raven
5
5
  class Backtrace
6
6
  # Handles backtrace parsing line by line
7
7
  class Line
8
+ RB_EXTENSION = ".rb".freeze
8
9
  # regexp (optional leading X: on windows, or JRuby9000 class-prefix)
9
10
  RUBY_INPUT_FORMAT = /
10
11
  ^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
@@ -34,7 +35,7 @@ module Raven
34
35
  ruby_match = unparsed_line.match(RUBY_INPUT_FORMAT)
35
36
  if ruby_match
36
37
  _, file, number, method = ruby_match.to_a
37
- file.sub!(/\.class$/, ".rb")
38
+ file.sub!(/\.class$/, RB_EXTENSION)
38
39
  module_name = nil
39
40
  else
40
41
  java_match = unparsed_line.match(JAVA_INPUT_FORMAT)
@@ -12,12 +12,15 @@ require 'raven/configuration'
12
12
  require 'raven/context'
13
13
  require 'raven/client'
14
14
  require 'raven/event'
15
+ require 'raven/linecache'
15
16
  require 'raven/logger'
16
17
  require 'raven/interfaces/message'
17
18
  require 'raven/interfaces/exception'
18
19
  require 'raven/interfaces/single_exception'
19
20
  require 'raven/interfaces/stack_trace'
20
21
  require 'raven/interfaces/http'
22
+ require 'raven/transports'
23
+ require 'raven/transports/http'
21
24
  require 'raven/utils/deep_merge'
22
25
  require 'raven/utils/real_ip'
23
26
  require 'raven/instance'
@@ -28,6 +31,9 @@ require 'English'
28
31
  module Raven
29
32
  AVAILABLE_INTEGRATIONS = %w(delayed_job railties sidekiq rack rack-timeout rake).freeze
30
33
 
34
+ class Error < StandardError
35
+ end
36
+
31
37
  class << self
32
38
  extend Forwardable
33
39
 
@@ -53,7 +53,7 @@ module Raven
53
53
 
54
54
  instance.logger.debug ""
55
55
  instance.logger.debug "Done!"
56
- true
56
+ evt
57
57
  end
58
58
  end
59
59
  end
@@ -3,9 +3,6 @@ require 'base64'
3
3
  require 'json'
4
4
  require 'zlib'
5
5
 
6
- require 'raven/version'
7
- require 'raven/transports/http'
8
-
9
6
  module Raven
10
7
  # Encodes events and sends them to the Sentry server.
11
8
  class Client
@@ -91,6 +91,10 @@ module Raven
91
91
  # We automatically try to set this to a git SHA or Capistrano release.
92
92
  attr_accessor :release
93
93
 
94
+ # The sampling factor to apply to events. A value of 0.0 will not send
95
+ # any events, and a value of 1.0 will send 100% of events.
96
+ attr_accessor :sample_rate
97
+
94
98
  # Boolean - sanitize values that look like credit card numbers
95
99
  attr_accessor :sanitize_credit_cards
96
100
 
@@ -161,7 +165,8 @@ module Raven
161
165
  'ActiveRecord::RecordNotFound',
162
166
  'CGI::Session::CookieStore::TamperedWithCookie',
163
167
  'Mongoid::Errors::DocumentNotFound',
164
- 'Sinatra::NotFound'
168
+ 'Sinatra::NotFound',
169
+ 'ActiveJob::DeserializationError'
165
170
  ].freeze
166
171
 
167
172
  # Note the order - we have to remove circular references and bad characters
@@ -176,11 +181,12 @@ module Raven
176
181
  ].freeze
177
182
 
178
183
  LOG_PREFIX = "** [Raven] ".freeze
184
+ MODULE_SEPARATOR = "::".freeze
179
185
 
180
186
  def initialize
181
187
  self.async = false
182
188
  self.context_lines = 3
183
- self.current_environment = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
189
+ self.current_environment = ENV['SENTRY_CURRENT_ENV'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
184
190
  self.encoding = 'gzip'
185
191
  self.environments = []
186
192
  self.exclude_loggers = []
@@ -194,13 +200,14 @@ module Raven
194
200
  self.rails_activesupport_breadcrumbs = false
195
201
  self.rails_report_rescued_exceptions = true
196
202
  self.release = detect_release
203
+ self.sample_rate = 1.0
197
204
  self.sanitize_credit_cards = true
198
205
  self.sanitize_fields = []
199
206
  self.sanitize_fields_excluded = []
200
207
  self.sanitize_http_headers = []
201
208
  self.send_modules = true
202
209
  self.server = ENV['SENTRY_DSN'] if ENV['SENTRY_DSN']
203
- self.server_name = resolve_hostname
210
+ self.server_name = heroku_dyno_name || resolve_hostname
204
211
  self.should_capture = false
205
212
  self.ssl_verification = true
206
213
  self.tags = {}
@@ -273,7 +280,8 @@ module Raven
273
280
 
274
281
  valid? &&
275
282
  capture_in_current_environment? &&
276
- capture_allowed_by_callback?(message_or_exc)
283
+ capture_allowed_by_callback?(message_or_exc) &&
284
+ sample_allowed?
277
285
  end
278
286
  # If we cannot capture, we cannot send.
279
287
  alias sending_allowed? capture_allowed?
@@ -304,8 +312,41 @@ module Raven
304
312
  end
305
313
  end
306
314
 
315
+ def exception_class_allowed?(exc)
316
+ if exc.is_a?(Raven::Error)
317
+ # Try to prevent error reporting loops
318
+ logger.debug "Refusing to capture Raven error: #{exc.inspect}"
319
+ false
320
+ elsif excluded_exception?(exc)
321
+ logger.debug "User excluded error: #{exc.inspect}"
322
+ false
323
+ else
324
+ true
325
+ end
326
+ end
327
+
307
328
  private
308
329
 
330
+ def excluded_exception?(exc)
331
+ excluded_exceptions.any? { |x| get_exception_class(x) === exc }
332
+ end
333
+
334
+ def get_exception_class(x)
335
+ x.is_a?(Module) ? x : qualified_const_get(x)
336
+ end
337
+
338
+ # In Ruby <2.0 const_get can't lookup "SomeModule::SomeClass" in one go
339
+ def qualified_const_get(x)
340
+ x = x.to_s
341
+ if !x.match(/::/)
342
+ Object.const_get(x)
343
+ else
344
+ x.split(MODULE_SEPARATOR).reject(&:empty?).inject(Object) { |a, e| a.const_get(e) }
345
+ end
346
+ rescue NameError # There's no way to safely ask if a constant exist for an unknown string
347
+ nil
348
+ end
349
+
309
350
  def detect_release_from_heroku
310
351
  return unless running_on_heroku?
311
352
  logger.warn(heroku_dyno_metadata_message) && return unless ENV['HEROKU_SLUG_COMMIT']
@@ -361,6 +402,21 @@ module Raven
361
402
  false
362
403
  end
363
404
 
405
+ def heroku_dyno_name
406
+ return unless running_on_heroku?
407
+ ENV['DYNO']
408
+ end
409
+
410
+ def sample_allowed?
411
+ return true if sample_rate == 1.0
412
+ if Random::DEFAULT.rand >= sample_rate
413
+ @errors << "Excluded by random sample"
414
+ false
415
+ else
416
+ true
417
+ end
418
+ end
419
+
364
420
  # Try to resolve the hostname to an FQDN, but fall back to whatever
365
421
  # the load name is.
366
422
  def resolve_hostname