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
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ #########################################
4
+ # This file was copied from Rails 5.2 #
5
+ #########################################
6
+
7
+ #--
8
+ # Most objects are cloneable, but not all. For example you can't dup methods:
9
+ #
10
+ # method(:puts).dup # => TypeError: allocator undefined for Method
11
+ #
12
+ # Classes may signal their instances are not duplicable removing +dup+/+clone+
13
+ # or raising exceptions from them. So, to dup an arbitrary object you normally
14
+ # use an optimistic approach and are ready to catch an exception, say:
15
+ #
16
+ # arbitrary_object.dup rescue object
17
+ #
18
+ # Rails dups objects in a few critical spots where they are not that arbitrary.
19
+ # That rescue is very expensive (like 40 times slower than a predicate), and it
20
+ # is often triggered.
21
+ #
22
+ # That's why we hardcode the following cases and check duplicable? instead of
23
+ # using that rescue idiom.
24
+ #++
25
+ class Object
26
+ # Can you safely dup this object?
27
+ #
28
+ # False for method objects;
29
+ # true otherwise.
30
+ def duplicable?
31
+ true
32
+ end
33
+ end
34
+
35
+ class NilClass
36
+ begin
37
+ nil.dup
38
+ rescue TypeError
39
+ # +nil+ is not duplicable:
40
+ #
41
+ # nil.duplicable? # => false
42
+ # nil.dup # => TypeError: can't dup NilClass
43
+ def duplicable?
44
+ false
45
+ end
46
+ end
47
+ end
48
+
49
+ class FalseClass
50
+ begin
51
+ false.dup
52
+ rescue TypeError
53
+ # +false+ is not duplicable:
54
+ #
55
+ # false.duplicable? # => false
56
+ # false.dup # => TypeError: can't dup FalseClass
57
+ def duplicable?
58
+ false
59
+ end
60
+ end
61
+ end
62
+
63
+ class TrueClass
64
+ begin
65
+ true.dup
66
+ rescue TypeError
67
+ # +true+ is not duplicable:
68
+ #
69
+ # true.duplicable? # => false
70
+ # true.dup # => TypeError: can't dup TrueClass
71
+ def duplicable?
72
+ false
73
+ end
74
+ end
75
+ end
76
+
77
+ class Symbol
78
+ begin
79
+ :symbol.dup # Ruby 2.4.x.
80
+ "symbol_from_string".to_sym.dup # Some symbols can't `dup` in Ruby 2.4.0.
81
+ rescue TypeError
82
+ # Symbols are not duplicable:
83
+ #
84
+ # :my_symbol.duplicable? # => false
85
+ # :my_symbol.dup # => TypeError: can't dup Symbol
86
+ def duplicable?
87
+ false
88
+ end
89
+ end
90
+ end
91
+
92
+ class Numeric
93
+ begin
94
+ 1.dup
95
+ rescue TypeError
96
+ # Numbers are not duplicable:
97
+ #
98
+ # 3.duplicable? # => false
99
+ # 3.dup # => TypeError: can't dup Integer
100
+ def duplicable?
101
+ false
102
+ end
103
+ end
104
+ end
105
+
106
+ require "bigdecimal"
107
+ class BigDecimal
108
+ # BigDecimals are duplicable:
109
+ #
110
+ # BigDecimal("1.2").duplicable? # => true
111
+ # BigDecimal("1.2").dup # => #<BigDecimal:...,'0.12E1',18(18)>
112
+ def duplicable?
113
+ true
114
+ end
115
+ end
116
+
117
+ class Method
118
+ # Methods are not duplicable:
119
+ #
120
+ # method(:puts).duplicable? # => false
121
+ # method(:puts).dup # => TypeError: allocator undefined for Method
122
+ def duplicable?
123
+ false
124
+ end
125
+ end
126
+
127
+ class Complex
128
+ begin
129
+ Complex(1).dup
130
+ rescue TypeError
131
+ # Complexes are not duplicable:
132
+ #
133
+ # Complex(1).duplicable? # => false
134
+ # Complex(1).dup # => TypeError: can't copy Complex
135
+ def duplicable?
136
+ false
137
+ end
138
+ end
139
+ end
140
+
141
+ class Rational
142
+ begin
143
+ Rational(1).dup
144
+ rescue TypeError
145
+ # Rationals are not duplicable:
146
+ #
147
+ # Rational(1).duplicable? # => false
148
+ # Rational(1).dup # => TypeError: can't copy Rational
149
+ def duplicable?
150
+ false
151
+ end
152
+ end
153
+ end
data/lib/raven/event.rb CHANGED
@@ -1,234 +1,125 @@
1
1
  # frozen_string_literal: true
2
- require 'rubygems'
2
+
3
3
  require 'socket'
4
4
  require 'securerandom'
5
- require 'digest/md5'
6
-
7
- require 'raven/error'
8
- require 'raven/linecache'
9
5
 
10
6
  module Raven
11
7
  class Event
12
- LOG_LEVELS = {
13
- "debug" => 10,
14
- "info" => 20,
15
- "warn" => 30,
16
- "warning" => 30,
17
- "error" => 40,
18
- "fatal" => 50
19
- }.freeze
20
-
21
- BACKTRACE_RE = /^(.+?):(\d+)(?::in `(.+?)')?$/
22
-
23
- PLATFORM = "ruby".freeze
24
- SDK = { "name" => "sentry-raven", "version" => Raven::VERSION }.freeze
25
-
26
- attr_accessor :id, :timestamp, :time_spent, :level, :logger,
27
- :culprit, :server_name, :release, :modules, :extra, :tags,
28
- :context, :configuration, :checksum, :fingerprint, :environment,
29
- :server_os, :runtime, :breadcrumbs, :user, :backtrace
30
-
31
- def initialize(init = {})
32
- @configuration = Raven.configuration
33
- @interfaces = {}
34
- @breadcrumbs = Raven.breadcrumbs
35
- @context = Raven.context
36
- @id = SecureRandom.uuid.delete("-")
37
- @timestamp = Time.now.utc
38
- @time_spent = nil
39
- @level = :error
40
- @logger = ''
41
- @culprit = nil
42
- @server_name = @configuration.server_name
43
- @release = @configuration.release
44
- @modules = list_gem_specs if @configuration.send_modules
45
- @user = {} # TODO: contexts
46
- @extra = {} # TODO: contexts
47
- @server_os = {} # TODO: contexts
48
- @runtime = {} # TODO: contexts
49
- @tags = {} # TODO: contexts
50
- @checksum = nil
51
- @fingerprint = nil
52
- @environment = @configuration.current_environment
53
-
54
- yield self if block_given?
55
-
56
- if !self[:http] && @context.rack_env
57
- interface :http do |int|
58
- int.from_rack(@context.rack_env)
59
- end
8
+ # See Sentry server default limits at
9
+ # https://github.com/getsentry/sentry/blob/master/src/sentry/conf/server.py
10
+ MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
11
+ REQUIRED_OPTION_KEYS = [:configuration, :context, :breadcrumbs].freeze
12
+
13
+ SDK = { "name" => "raven-ruby", "version" => Raven::VERSION }.freeze
14
+
15
+ attr_accessor :id, :logger, :transaction, :server_name, :release, :modules,
16
+ :extra, :tags, :context, :configuration, :checksum,
17
+ :fingerprint, :environment, :server_os, :runtime,
18
+ :breadcrumbs, :user, :backtrace, :platform, :sdk
19
+ alias event_id id
20
+
21
+ attr_reader :level, :timestamp, :time_spent
22
+
23
+ def initialize(options)
24
+ # Set some simple default values
25
+ self.id = SecureRandom.uuid.delete("-")
26
+ self.timestamp = Time.now.utc
27
+ self.level = :error
28
+ self.logger = :ruby
29
+ self.platform = :ruby
30
+ self.sdk = SDK
31
+
32
+ # Set some attributes with empty hashes to allow merging
33
+ @interfaces = {}
34
+ self.user = {} # TODO: contexts
35
+ self.extra = {} # TODO: contexts
36
+ self.server_os = {} # TODO: contexts
37
+ self.runtime = {} # TODO: contexts
38
+ self.tags = {} # TODO: contexts
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"
60
42
  end
61
43
 
62
- if @context.rack_env # TODO: contexts
63
- @context.user[:ip_address] = calculate_real_ip_from_rack
64
- end
65
-
66
- init.each_pair { |key, val| public_send(key.to_s + "=", val) }
44
+ self.configuration = options[:configuration]
45
+ self.context = options[:context]
46
+ self.breadcrumbs = options[:breadcrumbs]
67
47
 
68
- @user = @context.user.merge(@user) # TODO: contexts
69
- @extra = @context.extra.merge(@extra) # TODO: contexts
70
- @tags = @configuration.tags.merge(@context.tags).merge(@tags) # TODO: contexts
71
- @server_os = @context.server_os # TODO: contexts
72
- @runtime = @context.runtime # TODO: contexts
48
+ # Allow attributes to be set on the event at initialization
49
+ yield self if block_given?
50
+ options.each_pair { |key, val| public_send("#{key}=", val) unless val.nil? }
73
51
 
74
- # Some type coercion
75
- @timestamp = @timestamp.strftime('%Y-%m-%dT%H:%M:%S') if @timestamp.is_a?(Time)
76
- @time_spent = (@time_spent * 1000).to_i if @time_spent.is_a?(Float)
77
- @level = LOG_LEVELS[@level.to_s.downcase] if @level.is_a?(String) || @level.is_a?(Symbol)
52
+ set_core_attributes_from_configuration
53
+ set_core_attributes_from_context
78
54
  end
79
55
 
80
- def message
81
- @interfaces[:logentry] && @interfaces[:logentry].unformatted_message
82
- end
83
-
84
- def message=(args)
85
- message, params = *args
86
- interface(:message) do |int|
87
- int.message = message
88
- int.params = params
56
+ def self.from_exception(exc, options = {}, &block)
57
+ exception_context = if exc.instance_variable_defined?(:@__raven_context)
58
+ exc.instance_variable_get(:@__raven_context)
59
+ elsif exc.respond_to?(:raven_context)
60
+ exc.raven_context
61
+ else
62
+ {}
63
+ end
64
+ options = Raven::Utils::DeepMergeHash.deep_merge(exception_context, options)
65
+
66
+ return unless options[:configuration].exception_class_allowed?(exc)
67
+
68
+ new(options) do |evt|
69
+ evt.add_exception_interface(exc)
70
+ yield evt if block
89
71
  end
90
72
  end
91
73
 
92
- class << self
93
- def from_exception(exc, options = {}, &block)
94
- exception_context = get_exception_context(exc) || {}
95
- options = Raven::Utils::DeepMergeHash.deep_merge(exception_context, options)
96
-
97
- configuration = options[:configuration] || Raven.configuration
98
- if exc.is_a?(Raven::Error)
99
- # Try to prevent error reporting loops
100
- Raven.logger.info "Refusing to capture Raven error: #{exc.inspect}"
101
- return nil
102
- end
103
- if configuration[:excluded_exceptions].any? { |x| get_exception_class(x) === exc }
104
- Raven.logger.info "User excluded error: #{exc.inspect}"
105
- return nil
106
- end
107
-
108
- new(options) do |evt|
109
- evt.configuration = configuration
110
- evt.message = "#{exc.class}: #{exc.message}"
111
- evt.level = options[:level] || :error
112
-
113
- add_exception_interface(evt, exc)
114
-
115
- yield evt if block
116
- end
117
- end
118
-
119
- def from_message(message, options = {})
120
- message = message.byteslice(0...10_000) # Messages limited to 10kb
121
- configuration = options[:configuration] || Raven.configuration
122
-
123
- new(options) do |evt|
124
- evt.configuration = configuration
125
- evt.level = options[:level] || :error
126
- evt.message = message, options[:message_params] || []
127
- if options[:backtrace]
128
- evt.interface(:stacktrace) do |int|
129
- stacktrace_interface_from(int, evt, options[:backtrace])
130
- end
74
+ def self.from_message(message, options = {})
75
+ new(options) do |evt|
76
+ evt.message = message, options[:message_params] || []
77
+ if options[:backtrace]
78
+ evt.interface(:stacktrace) do |int|
79
+ int.frames = evt.stacktrace_interface_from(options[:backtrace])
131
80
  end
132
81
  end
133
82
  end
83
+ end
134
84
 
135
- private
136
-
137
- def get_exception_class(x)
138
- x.is_a?(Module) ? x : qualified_const_get(x)
139
- end
140
-
141
- # In Ruby <2.0 const_get can't lookup "SomeModule::SomeClass" in one go
142
- def qualified_const_get(x)
143
- x = x.to_s
144
- parts = x.split("::")
145
- parts.reject!(&:empty?)
85
+ def message
86
+ @interfaces[:logentry]&.unformatted_message
87
+ end
146
88
 
147
- if parts.size < 2
148
- Object.const_get(x)
149
- else
150
- parts.inject(Object) { |a, e| a.const_get(e) }
151
- end
152
- rescue NameError # There's no way to safely ask if a constant exist for an unknown string
153
- nil
89
+ def message=(args)
90
+ if args.is_a?(Array)
91
+ message, params = args[0], args[0..-1]
92
+ else
93
+ message = args
154
94
  end
155
95
 
156
- def get_exception_context(exc)
157
- if exc.instance_variable_defined?(:@__raven_context)
158
- exc.instance_variable_get(:@__raven_context)
159
- elsif exc.respond_to?(:raven_context)
160
- exc.raven_context
161
- end
96
+ unless message.is_a?(String)
97
+ configuration.logger.debug("You're passing a non-string message")
98
+ message = message.to_s
162
99
  end
163
100
 
164
- def add_exception_interface(evt, exc)
165
- evt.interface(:exception) do |exc_int|
166
- exceptions = [exc]
167
- context = Set.new [exc.object_id]
168
- backtraces = Set.new
169
-
170
- while exc.respond_to?(:cause) && exc.cause
171
- exc = exc.cause
172
- break if context.include?(exc.object_id)
173
- exceptions << exc
174
- context.add(exc.object_id)
175
- end
176
- exceptions.reverse!
177
-
178
- exc_int.values = exceptions.map do |e|
179
- SingleExceptionInterface.new do |int|
180
- int.type = e.class.to_s
181
- int.value = e.to_s
182
- int.module = e.class.to_s.split('::')[0...-1].join('::')
183
-
184
- int.stacktrace =
185
- if e.backtrace && !backtraces.include?(e.backtrace.object_id)
186
- backtraces << e.backtrace.object_id
187
- StacktraceInterface.new do |stacktrace|
188
- stacktrace_interface_from(stacktrace, evt, e.backtrace)
189
- end
190
- end
191
- end
192
- end
193
- end
101
+ interface(:message) do |int|
102
+ int.message = message.byteslice(0...MAX_MESSAGE_SIZE_IN_BYTES) # Messages limited to 10kb
103
+ int.params = params
194
104
  end
105
+ end
195
106
 
196
- def stacktrace_interface_from(int, evt, backtrace)
197
- backtrace = Backtrace.parse(backtrace)
198
-
199
- int.frames = []
200
- backtrace.lines.reverse_each do |line|
201
- frame = StacktraceInterface::Frame.new
202
- frame.abs_path = line.file if line.file
203
- frame.function = line.method if line.method
204
- frame.lineno = line.number
205
- frame.in_app = line.in_app
206
- frame.module = line.module_name if line.module_name
207
-
208
- if evt.configuration[:context_lines] && frame.abs_path
209
- frame.pre_context, frame.context_line, frame.post_context = \
210
- evt.get_file_context(frame.abs_path, frame.lineno, evt.configuration[:context_lines])
211
- end
212
-
213
- int.frames << frame if frame.filename
214
- end
215
-
216
- evt.culprit = evt.get_culprit(int.frames)
217
- end
107
+ def timestamp=(time)
108
+ @timestamp = time.is_a?(Time) ? time.strftime('%Y-%m-%dT%H:%M:%S') : time
109
+ end
218
110
 
219
- # Because linecache can go to hell
220
- def _source_lines(_path, _from, _to)
221
- end
111
+ def time_spent=(time)
112
+ @time_spent = time.is_a?(Float) ? (time * 1000).to_i : time
222
113
  end
223
114
 
224
- def list_gem_specs
225
- # Older versions of Rubygems don't support iterating over all specs
226
- Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
115
+ def level=(new_level) # needed to meet the Sentry spec
116
+ @level = new_level.to_s == "warn" ? :warning : new_level
227
117
  end
228
118
 
229
119
  def interface(name, value = nil, &block)
230
120
  int = Interface.registered[name]
231
121
  raise(Error, "Unknown interface: #{name}") unless int
122
+
232
123
  @interfaces[int.sentry_alias] = int.new(value, &block) if value || block
233
124
  @interfaces[int.sentry_alias]
234
125
  end
@@ -242,54 +133,63 @@ module Raven
242
133
  end
243
134
 
244
135
  def to_hash
245
- data = {
246
- :event_id => @id,
247
- :timestamp => @timestamp,
248
- :time_spent => @time_spent,
249
- :level => @level,
250
- :platform => PLATFORM,
251
- :sdk => SDK,
252
- :contexts => {
253
- :server_os => @server_os,
254
- :runtime => @runtime
255
- }
256
- }
257
-
258
- data[:logger] = @logger if @logger
259
- data[:culprit] = @culprit if @culprit
260
- data[:server_name] = @server_name if @server_name
261
- data[:release] = @release if @release
262
- data[:environment] = @environment if @environment
263
- data[:fingerprint] = @fingerprint if @fingerprint
264
- data[:modules] = @modules if @modules
265
- data[:extra] = @extra if @extra
266
- data[:tags] = @tags if @tags
267
- data[:user] = @user if @user
136
+ data = [:checksum, :environment, :event_id, :extra, :fingerprint, :level,
137
+ :logger, :message, :modules, :platform, :release, :sdk, :server_name,
138
+ :tags, :time_spent, :timestamp, :transaction, :user].each_with_object({}) do |att, memo|
139
+ memo[att] = public_send(att) if public_send(att)
140
+ end
141
+
268
142
  data[:breadcrumbs] = @breadcrumbs.to_hash unless @breadcrumbs.empty?
269
- data[:checksum] = @checksum if @checksum
270
143
 
271
144
  @interfaces.each_pair do |name, int_data|
272
145
  data[name.to_sym] = int_data.to_hash
273
146
  end
274
- data[:message] = message
275
147
  data
276
148
  end
277
149
 
278
- def get_file_context(filename, lineno, context)
279
- return nil, nil, nil unless Raven::LineCache.valid_file?(filename)
280
- lines = Array.new(2 * context + 1) do |i|
281
- Raven::LineCache.getline(filename, lineno - context + i)
282
- end
283
- [lines[0..(context - 1)], lines[context], lines[(context + 1)..-1]]
150
+ def to_json_compatible
151
+ cleaned_hash = async_json_processors.reduce(to_hash) { |a, e| e.process(a) }
152
+ JSON.parse(JSON.generate(cleaned_hash))
284
153
  end
285
154
 
286
- def get_culprit(frames)
287
- lastframe = frames.reverse.find(&:in_app) || frames.last
288
- "#{lastframe.filename} in #{lastframe.function} at line #{lastframe.lineno}" if lastframe
155
+ def add_exception_interface(exc)
156
+ interface(:exception) do |exc_int|
157
+ exceptions = Raven::Utils::ExceptionCauseChain.exception_to_array(exc).reverse
158
+ backtraces = Set.new
159
+ exc_int.values = exceptions.map do |e|
160
+ SingleExceptionInterface.new do |int|
161
+ int.type = e.class.to_s
162
+ int.value = e.to_s
163
+ int.module = e.class.to_s.split('::')[0...-1].join('::')
164
+
165
+ int.stacktrace =
166
+ if e.backtrace && !backtraces.include?(e.backtrace.object_id)
167
+ backtraces << e.backtrace.object_id
168
+ StacktraceInterface.new do |stacktrace|
169
+ stacktrace.frames = stacktrace_interface_from(e.backtrace)
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
289
175
  end
290
176
 
291
- def to_json_compatible
292
- JSON.parse(JSON.generate(to_hash))
177
+ def stacktrace_interface_from(backtrace)
178
+ Backtrace.parse(backtrace, { configuration: configuration }).lines.reverse.each_with_object([]) do |line, memo|
179
+ frame = StacktraceInterface::Frame.new
180
+ frame.abs_path = line.file if line.file
181
+ frame.function = line.method if line.method
182
+ frame.lineno = line.number
183
+ frame.in_app = line.in_app
184
+ frame.module = line.module_name if line.module_name
185
+
186
+ if configuration[:context_lines] && frame.abs_path
187
+ frame.pre_context, frame.context_line, frame.post_context = \
188
+ configuration.linecache.get_file_context(frame.abs_path, frame.lineno, configuration[:context_lines])
189
+ end
190
+
191
+ memo << frame if frame.filename
192
+ end
293
193
  end
294
194
 
295
195
  # For cross-language compat
@@ -302,6 +202,36 @@ module Raven
302
202
 
303
203
  private
304
204
 
205
+ def set_core_attributes_from_configuration
206
+ self.server_name ||= configuration.server_name
207
+ self.release ||= configuration.release
208
+ self.modules = list_gem_specs if configuration.send_modules
209
+ self.environment ||= configuration.current_environment
210
+ end
211
+
212
+ def set_core_attributes_from_context
213
+ self.transaction ||= context.transaction.last
214
+
215
+ # If this is a Rack event, merge Rack context
216
+ add_rack_context if !self[:http] && context.rack_env
217
+
218
+ # Merge contexts
219
+ self.user = context.user.merge(user) # TODO: contexts
220
+ self.extra = context.extra.merge(extra) # TODO: contexts
221
+ self.tags = configuration.tags.merge(context.tags).merge!(tags) # TODO: contexts
222
+ end
223
+
224
+ def add_rack_context
225
+ interface :http do |int|
226
+ int.from_rack(context.rack_env)
227
+ end
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
233
+ end
234
+
305
235
  # When behind a proxy (or if the user is using a proxy), we can't use
306
236
  # REMOTE_ADDR to determine the Event IP, and must use other headers instead.
307
237
  def calculate_real_ip_from_rack
@@ -312,5 +242,14 @@ module Raven
312
242
  :forwarded_for => context.rack_env["HTTP_X_FORWARDED_FOR"]
313
243
  ).calculate_ip
314
244
  end
245
+
246
+ def async_json_processors
247
+ configuration.processors.map { |v| v.new(self) }
248
+ end
249
+
250
+ def list_gem_specs
251
+ # Older versions of Rubygems don't support iterating over all specs
252
+ Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
253
+ end
315
254
  end
316
255
  end
@@ -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