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
@@ -1,4 +1,3 @@
1
- require 'logger'
2
1
  require 'uri'
3
2
 
4
3
  module Raven
@@ -13,6 +12,11 @@ module Raven
13
12
  attr_reader :async
14
13
  alias async? async
15
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
+
16
20
  # Number of lines of code context to capture, or nil for none
17
21
  attr_accessor :context_lines
18
22
 
@@ -32,12 +36,25 @@ module Raven
32
36
  # You should probably append to this rather than overwrite it.
33
37
  attr_accessor :excluded_exceptions
34
38
 
39
+ # Boolean to check nested exceptions when deciding if to exclude. Defaults to false
40
+ attr_accessor :inspect_exception_causes_for_exclusion
41
+ alias inspect_exception_causes_for_exclusion? inspect_exception_causes_for_exclusion
42
+
35
43
  # DSN component - set automatically if DSN provided
36
44
  attr_accessor :host
37
45
 
38
46
  # The Faraday adapter to be used. Will default to Net::HTTP when not set.
39
47
  attr_accessor :http_adapter
40
48
 
49
+ # A Proc yeilding the faraday builder allowing for further configuration
50
+ # of the faraday adapter
51
+ attr_accessor :faraday_builder
52
+
53
+ # You may provide your own LineCache for matching paths with source files.
54
+ # This may be useful if you need to get source code from places other than
55
+ # the disk. See Raven::LineCache for the required interface you must implement.
56
+ attr_accessor :linecache
57
+
41
58
  # Logger used by Raven. In Rails, this is the Rails logger, otherwise
42
59
  # Raven provides its own Raven::Logger.
43
60
  attr_accessor :logger
@@ -71,7 +88,7 @@ module Raven
71
88
  attr_accessor :public_key
72
89
 
73
90
  # Turns on ActiveSupport breadcrumbs integration
74
- attr_accessor :rails_activesupport_breadcrumbs
91
+ attr_reader :rails_activesupport_breadcrumbs
75
92
 
76
93
  # Rails catches exceptions in the ActionDispatch::ShowExceptions or
77
94
  # ActionDispatch::DebugExceptions middlewares, depending on the environment.
@@ -83,6 +100,10 @@ module Raven
83
100
  # We automatically try to set this to a git SHA or Capistrano release.
84
101
  attr_accessor :release
85
102
 
103
+ # The sampling factor to apply to events. A value of 0.0 will not send
104
+ # any events, and a value of 1.0 will send 100% of events.
105
+ attr_accessor :sample_rate
106
+
86
107
  # Boolean - sanitize values that look like credit card numbers
87
108
  attr_accessor :sanitize_credit_cards
88
109
 
@@ -91,6 +112,10 @@ module Raven
91
112
  # a hash key, will be censored and not sent to Sentry.
92
113
  attr_accessor :sanitize_fields
93
114
 
115
+ # If you're sure you want to override the default sanitization values, you can
116
+ # add to them to an array of Strings here, e.g. %w(authorization password)
117
+ attr_accessor :sanitize_fields_excluded
118
+
94
119
  # Sanitize additional HTTP headers - only Authorization is removed by default.
95
120
  attr_accessor :sanitize_http_headers
96
121
 
@@ -98,8 +123,23 @@ module Raven
98
123
  # Otherwise, can be one of "http", "https", or "dummy"
99
124
  attr_accessor :scheme
100
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
+
101
139
  # Secret key for authentication with the Sentry server
102
140
  # If you provide a DSN, this will be set automatically.
141
+ #
142
+ # This is deprecated and not necessary for newer Sentry installations any more.
103
143
  attr_accessor :secret_key
104
144
 
105
145
  # Include module versions in reports - boolean.
@@ -114,7 +154,7 @@ module Raven
114
154
  # Note that the object passed into the block will be a String (messages) or
115
155
  # an exception.
116
156
  # e.g. lambda { |exc_or_msg| exc_or_msg.some_attr == false }
117
- attr_accessor :should_capture
157
+ attr_reader :should_capture
118
158
 
119
159
  # Silences ready message when true.
120
160
  attr_accessor :silence_ready
@@ -138,14 +178,45 @@ module Raven
138
178
  # E.g. lambda { |event| Thread.new { MyJobProcessor.send_email(event) } }
139
179
  attr_reader :transport_failure_callback
140
180
 
181
+ # Optional Proc, called before sending an event to the server/
182
+ # E.g.: lambda { |event, hint| event }
183
+ # E.g.: lambda { |event, hint| nil }
184
+ # E.g.: lambda { |event, hint|
185
+ # event[:message] = 'a'
186
+ # event
187
+ # }
188
+ attr_reader :before_send
189
+
190
+ # Errors object - an Array that contains error messages. See #
191
+ attr_reader :errors
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.
141
201
  IGNORE_DEFAULT = [
142
202
  'AbstractController::ActionNotFound',
203
+ 'ActionController::BadRequest',
143
204
  'ActionController::InvalidAuthenticityToken',
205
+ 'ActionController::InvalidCrossOriginRequest',
206
+ 'ActionController::MethodNotAllowed',
207
+ 'ActionController::NotImplemented',
208
+ 'ActionController::ParameterMissing',
144
209
  'ActionController::RoutingError',
145
210
  'ActionController::UnknownAction',
211
+ 'ActionController::UnknownFormat',
212
+ 'ActionController::UnknownHttpMethod',
213
+ 'ActionDispatch::Http::Parameters::ParseError',
214
+ 'ActiveJob::DeserializationError', # Can cause infinite loops
146
215
  'ActiveRecord::RecordNotFound',
147
216
  'CGI::Session::CookieStore::TamperedWithCookie',
148
217
  'Mongoid::Errors::DocumentNotFound',
218
+ 'Rack::QueryParser::InvalidParameterError',
219
+ 'Rack::QueryParser::ParameterTypeError',
149
220
  'Sinatra::NotFound'
150
221
  ].freeze
151
222
 
@@ -160,34 +231,61 @@ module Raven
160
231
  Raven::Processor::HTTPHeaders
161
232
  ].freeze
162
233
 
234
+ HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
235
+ "release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`".freeze
236
+
237
+ RACK_ENV_WHITELIST_DEFAULT = %w(
238
+ REMOTE_ADDR
239
+ SERVER_NAME
240
+ SERVER_PORT
241
+ ).freeze
242
+
243
+ LOG_PREFIX = "** [Raven] ".freeze
244
+ MODULE_SEPARATOR = "::".freeze
245
+
246
+ AVAILABLE_BREADCRUMBS_LOGGERS = [:sentry_logger, :active_support_logger].freeze
247
+
163
248
  def initialize
164
249
  self.async = false
250
+ self.breadcrumbs_logger = []
165
251
  self.context_lines = 3
166
- self.current_environment = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
252
+ self.current_environment = current_environment_from_env
167
253
  self.encoding = 'gzip'
168
254
  self.environments = []
169
255
  self.exclude_loggers = []
170
256
  self.excluded_exceptions = IGNORE_DEFAULT.dup
257
+ self.inspect_exception_causes_for_exclusion = false
258
+ self.linecache = ::Raven::LineCache.new
259
+ self.logger = ::Raven::Logger.new(STDOUT)
171
260
  self.open_timeout = 1
172
261
  self.processors = DEFAULT_PROCESSORS.dup
173
- self.proxy = nil
174
- self.rails_activesupport_breadcrumbs = false
262
+ self.project_root = detect_project_root
263
+ @rails_activesupport_breadcrumbs = false
264
+
175
265
  self.rails_report_rescued_exceptions = true
176
266
  self.release = detect_release
267
+ self.sample_rate = 1.0
177
268
  self.sanitize_credit_cards = true
178
269
  self.sanitize_fields = []
270
+ self.sanitize_fields_excluded = []
179
271
  self.sanitize_http_headers = []
180
272
  self.send_modules = true
181
- self.server = ENV['SENTRY_DSN'] if ENV['SENTRY_DSN']
182
- self.server_name = resolve_hostname
273
+ self.server = ENV['SENTRY_DSN']
274
+ self.server_name = server_name_from_env
183
275
  self.should_capture = false
184
276
  self.ssl_verification = true
185
277
  self.tags = {}
186
278
  self.timeout = 2
187
279
  self.transport_failure_callback = false
280
+ self.before_send = false
281
+ self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
188
282
  end
189
283
 
190
284
  def server=(value)
285
+ return if value.nil?
286
+
287
+ @dsn = value
288
+
191
289
  uri = URI.parse(value)
192
290
  uri_path = uri.path.split('/')
193
291
 
@@ -195,7 +293,7 @@ module Raven
195
293
  # DSN-style string
196
294
  self.project_id = uri_path.pop
197
295
  self.public_key = uri.user
198
- self.secret_key = uri.password
296
+ self.secret_key = !(uri.password.nil? || uri.password.empty?) ? uri.password : nil
199
297
  end
200
298
 
201
299
  self.scheme = uri.scheme
@@ -205,13 +303,14 @@ module Raven
205
303
 
206
304
  # For anyone who wants to read the base server string
207
305
  @server = "#{scheme}://#{host}"
208
- @server << ":#{port}" unless port == { 'http' => 80, 'https' => 443 }[scheme]
209
- @server << path
306
+ @server += ":#{port}" unless port == { 'http' => 80, 'https' => 443 }[scheme]
307
+ @server += path
210
308
  end
211
309
  alias dsn= server=
212
310
 
213
311
  def encoding=(encoding)
214
312
  raise(Error, 'Unsupported encoding') unless %w(gzip json).include? encoding
313
+
215
314
  @encoding = encoding
216
315
  end
217
316
 
@@ -219,13 +318,32 @@ module Raven
219
318
  unless value == false || value.respond_to?(:call)
220
319
  raise(ArgumentError, "async must be callable (or false to disable)")
221
320
  end
321
+
222
322
  @async = value
223
323
  end
224
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
+
225
342
  def transport_failure_callback=(value)
226
343
  unless value == false || value.respond_to?(:call)
227
344
  raise(ArgumentError, "transport_failure_callback must be callable (or false to disable)")
228
345
  end
346
+
229
347
  @transport_failure_callback = value
230
348
  end
231
349
 
@@ -233,9 +351,18 @@ module Raven
233
351
  unless value == false || value.respond_to?(:call)
234
352
  raise ArgumentError, "should_capture must be callable (or false to disable)"
235
353
  end
354
+
236
355
  @should_capture = value
237
356
  end
238
357
 
358
+ def before_send=(value)
359
+ unless value == false || value.respond_to?(:call)
360
+ raise ArgumentError, "before_send must be callable (or false to disable)"
361
+ end
362
+
363
+ @before_send = value
364
+ end
365
+
239
366
  # Allows config options to be read like a hash
240
367
  #
241
368
  # @param [Symbol] option Key for a given attribute
@@ -248,17 +375,19 @@ module Raven
248
375
  end
249
376
 
250
377
  def capture_allowed?(message_or_exc = nil)
251
- capture_in_current_environment? &&
252
- capture_allowed_by_callback?(message_or_exc)
253
- end
378
+ @errors = []
254
379
 
380
+ valid? &&
381
+ capture_in_current_environment? &&
382
+ capture_allowed_by_callback?(message_or_exc) &&
383
+ sample_allowed?
384
+ end
255
385
  # If we cannot capture, we cannot send.
256
386
  alias sending_allowed? capture_allowed?
257
387
 
258
- def verify!
259
- %w(server public_key secret_key project_id).each do |key|
260
- raise(Error, "No #{key} specified") unless public_send key
261
- end
388
+ def error_messages
389
+ @errors = [errors[0]] + errors[1..-1].map(&:downcase) # fix case of all but first
390
+ errors.join(", ")
262
391
  end
263
392
 
264
393
  def project_root=(root_dir)
@@ -266,45 +395,144 @@ module Raven
266
395
  Backtrace::Line.instance_variable_set(:@in_app_pattern, nil) # blow away cache
267
396
  end
268
397
 
398
+ def rails_activesupport_breadcrumbs=(val)
399
+ DeprecationHelper.deprecate_old_breadcrumbs_configuration(:active_support_logger)
400
+ @rails_activesupport_breadcrumbs = val
401
+ end
402
+
403
+ def exception_class_allowed?(exc)
404
+ if exc.is_a?(Raven::Error)
405
+ # Try to prevent error reporting loops
406
+ logger.debug "Refusing to capture Raven error: #{exc.inspect}"
407
+ false
408
+ elsif excluded_exception?(exc)
409
+ logger.debug "User excluded error: #{exc.inspect}"
410
+ false
411
+ else
412
+ true
413
+ end
414
+ end
415
+
416
+ def enabled_in_current_env?
417
+ environments.empty? || environments.include?(current_environment)
418
+ end
419
+
420
+ private
421
+
422
+ def detect_project_root
423
+ if defined? Rails.root # we are in a Rails application
424
+ Rails.root.to_s
425
+ else
426
+ Dir.pwd
427
+ end
428
+ end
429
+
269
430
  def detect_release
270
- detect_release_from_git ||
431
+ detect_release_from_env ||
432
+ detect_release_from_git ||
271
433
  detect_release_from_capistrano ||
272
434
  detect_release_from_heroku
435
+ rescue => e
436
+ logger.error "Error detecting release: #{e.message}"
273
437
  end
274
438
 
275
- private
439
+ def excluded_exception?(incoming_exception)
440
+ excluded_exceptions.any? do |excluded_exception|
441
+ matches_exception?(get_exception_class(excluded_exception), incoming_exception)
442
+ end
443
+ end
276
444
 
277
- def detect_release_from_heroku
278
- sys_dyno_info = File.read("/etc/heroku/dyno").strip if File.directory?("/etc/heroku") rescue nil
279
- return unless sys_dyno_info
280
-
281
- # being overly cautious, because if we raise an error Raven won't start
282
- begin
283
- hash = JSON.parse(sys_dyno_info)
284
- hash && hash["release"] && hash["release"]["commit"]
285
- rescue JSON::JSONError
286
- Raven.logger.error "Cannot parse Heroku JSON: #{sys_dyno_info}"
445
+ def get_exception_class(x)
446
+ x.is_a?(Module) ? x : qualified_const_get(x)
447
+ end
448
+
449
+ def matches_exception?(excluded_exception_class, incoming_exception)
450
+ if inspect_exception_causes_for_exclusion?
451
+ Raven::Utils::ExceptionCauseChain.exception_to_array(incoming_exception).any? { |cause| excluded_exception_class === cause }
452
+ else
453
+ excluded_exception_class === incoming_exception
454
+ end
455
+ end
456
+
457
+ # In Ruby <2.0 const_get can't lookup "SomeModule::SomeClass" in one go
458
+ def qualified_const_get(x)
459
+ x = x.to_s
460
+ if !x.match(/::/)
461
+ Object.const_get(x)
462
+ else
463
+ x.split(MODULE_SEPARATOR).reject(&:empty?).inject(Object) { |a, e| a.const_get(e) }
287
464
  end
465
+ rescue NameError # There's no way to safely ask if a constant exist for an unknown string
466
+ nil
467
+ end
468
+
469
+ def detect_release_from_heroku
470
+ return unless running_on_heroku?
471
+ return if ENV['CI']
472
+ logger.warn(HEROKU_DYNO_METADATA_MESSAGE) && return unless ENV['HEROKU_SLUG_COMMIT']
473
+
474
+ ENV['HEROKU_SLUG_COMMIT']
475
+ end
476
+
477
+ def running_on_heroku?
478
+ File.directory?("/etc/heroku")
288
479
  end
289
480
 
290
481
  def detect_release_from_capistrano
291
- version = File.read(File.join(project_root, 'REVISION')).strip rescue nil
482
+ revision_file = File.join(project_root, 'REVISION')
483
+ revision_log = File.join(project_root, '..', 'revisions.log')
292
484
 
293
- # Capistrano 3.0 - 3.1.x
294
- version || File.open(File.join(project_root, '..', 'revisions.log')).to_a.last.strip.sub(/.*as release ([0-9]+).*/, '\1') rescue nil
485
+ if File.exist?(revision_file)
486
+ File.read(revision_file).strip
487
+ elsif File.exist?(revision_log)
488
+ File.open(revision_log).to_a.last.strip.sub(/.*as release ([0-9]+).*/, '\1')
489
+ end
295
490
  end
296
491
 
297
492
  def detect_release_from_git
298
- `git rev-parse --short HEAD`.strip if File.directory?(".git") rescue nil
493
+ Raven.sys_command("git rev-parse --short HEAD") if File.directory?(".git")
494
+ end
495
+
496
+ def detect_release_from_env
497
+ ENV['SENTRY_RELEASE']
299
498
  end
300
499
 
301
500
  def capture_in_current_environment?
302
- !!server && (environments.empty? || environments.include?(current_environment))
501
+ return true if enabled_in_current_env?
502
+
503
+ @errors << "Not configured to send/capture in environment '#{current_environment}'"
504
+ false
303
505
  end
304
506
 
305
507
  def capture_allowed_by_callback?(message_or_exc)
306
- return true if !should_capture || message_or_exc.nil?
307
- should_capture.call(*[message_or_exc])
508
+ return true if !should_capture || message_or_exc.nil? || should_capture.call(message_or_exc)
509
+
510
+ @errors << "should_capture returned false"
511
+ false
512
+ end
513
+
514
+ def valid?
515
+ return true if %w(server host path public_key project_id).all? { |k| public_send(k) }
516
+
517
+ if server
518
+ %w(server host path public_key project_id).map do |key|
519
+ @errors << "No #{key} specified" unless public_send(key)
520
+ end
521
+ else
522
+ @errors << "DSN not set"
523
+ end
524
+ false
525
+ end
526
+
527
+ def sample_allowed?
528
+ return true if sample_rate == 1.0
529
+
530
+ if Random::DEFAULT.rand >= sample_rate
531
+ @errors << "Excluded by random sample"
532
+ false
533
+ else
534
+ true
535
+ end
308
536
  end
309
537
 
310
538
  # Try to resolve the hostname to an FQDN, but fall back to whatever
@@ -313,5 +541,17 @@ module Raven
313
541
  Socket.gethostname ||
314
542
  Socket.gethostbyname(hostname).first rescue server_name
315
543
  end
544
+
545
+ def current_environment_from_env
546
+ ENV['SENTRY_CURRENT_ENV'] || ENV['SENTRY_ENVIRONMENT'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
547
+ end
548
+
549
+ def server_name_from_env
550
+ if running_on_heroku?
551
+ ENV['DYNO']
552
+ else
553
+ resolve_hostname
554
+ end
555
+ end
316
556
  end
317
557
  end
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
@@ -10,31 +11,36 @@ module Raven
10
11
  Thread.current[:sentry_context] = nil
11
12
  end
12
13
 
13
- attr_accessor :extra, :server_os, :rack_env, :runtime, :tags, :user
14
+ attr_accessor :transaction, :extra, :server_os, :rack_env, :runtime, :tags, :user
14
15
 
15
16
  def initialize
16
- self.extra = {}
17
17
  self.server_os = self.class.os_context
18
- self.rack_env = nil
19
18
  self.runtime = self.class.runtime_context
19
+ self.extra = { :server => { :os => server_os, :runtime => runtime } }
20
+ self.rack_env = nil
20
21
  self.tags = {}
21
22
  self.user = {}
23
+ self.transaction = []
22
24
  end
23
25
 
24
26
  class << self
25
27
  def os_context
26
- @os_context ||= {
27
- "name" => Raven.sys_command("uname -s") || RbConfig::CONFIG["host_os"],
28
- "version" => Raven.sys_command("uname -v"),
29
- "build" => Raven.sys_command("uname -r"),
30
- "kernel_version" => Raven.sys_command("uname -a") || Raven.sys_command("ver") # windows
31
- }
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
32
38
  end
33
39
 
34
40
  def runtime_context
35
41
  @runtime_context ||= {
36
- "name" => RbConfig::CONFIG["ruby_install_name"],
37
- "version" => Raven.sys_command("ruby -v")
42
+ name: RbConfig::CONFIG["ruby_install_name"],
43
+ version: RUBY_DESCRIPTION || Raven.sys_command("ruby -v")
38
44
  }
39
45
  end
40
46
  end
@@ -0,0 +1,57 @@
1
+ require 'raven/core_ext/object/duplicable'
2
+
3
+ #########################################
4
+ # This file was copied from Rails 5.2 #
5
+ #########################################
6
+
7
+ class Object
8
+ # Returns a deep copy of object if it's duplicable. If it's
9
+ # not duplicable, returns +self+.
10
+ #
11
+ # object = Object.new
12
+ # dup = object.deep_dup
13
+ # dup.instance_variable_set(:@a, 1)
14
+ #
15
+ # object.instance_variable_defined?(:@a) # => false
16
+ # dup.instance_variable_defined?(:@a) # => true
17
+ def deep_dup
18
+ duplicable? ? dup : self
19
+ end
20
+ end
21
+
22
+ class Array
23
+ # Returns a deep copy of array.
24
+ #
25
+ # array = [1, [2, 3]]
26
+ # dup = array.deep_dup
27
+ # dup[1][2] = 4
28
+ #
29
+ # array[1][2] # => nil
30
+ # dup[1][2] # => 4
31
+ def deep_dup
32
+ map(&:deep_dup)
33
+ end
34
+ end
35
+
36
+ class Hash
37
+ # Returns a deep copy of hash.
38
+ #
39
+ # hash = { a: { b: 'b' } }
40
+ # dup = hash.deep_dup
41
+ # dup[:a][:c] = 'c'
42
+ #
43
+ # hash[:a][:c] # => nil
44
+ # dup[:a][:c] # => "c"
45
+ def deep_dup
46
+ hash = dup
47
+ each_pair do |key, value|
48
+ if key.frozen? && ::String === key
49
+ hash[key] = value.deep_dup
50
+ else
51
+ hash.delete(key)
52
+ hash[key.deep_dup] = value.deep_dup
53
+ end
54
+ end
55
+ hash
56
+ end
57
+ end