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.
- checksums.yaml +5 -5
- data/.craft.yml +19 -0
- data/.scripts/bump-version.rb +5 -0
- data/CHANGELOG.md +703 -0
- data/Gemfile +37 -0
- data/Makefile +3 -0
- data/README.md +116 -18
- data/Rakefile +30 -0
- data/exe/raven +32 -0
- data/lib/raven/backtrace.rb +16 -6
- data/lib/raven/base.rb +17 -4
- data/lib/raven/breadcrumbs/{activesupport.rb → active_support_logger.rb} +9 -3
- data/lib/raven/breadcrumbs/logger.rb +2 -92
- data/lib/raven/breadcrumbs/sentry_logger.rb +73 -0
- data/lib/raven/breadcrumbs.rb +3 -1
- data/lib/raven/cli.rb +31 -43
- data/lib/raven/client.rb +39 -17
- data/lib/raven/configuration.rb +277 -37
- data/lib/raven/context.rb +17 -11
- data/lib/raven/core_ext/object/deep_dup.rb +57 -0
- data/lib/raven/core_ext/object/duplicable.rb +153 -0
- data/lib/raven/event.rb +172 -233
- data/lib/raven/helpers/deprecation_helper.rb +17 -0
- data/lib/raven/instance.rb +51 -25
- data/lib/raven/integrations/delayed_job.rb +18 -18
- data/lib/raven/integrations/rack-timeout.rb +11 -5
- data/lib/raven/integrations/rack.rb +36 -19
- data/lib/raven/integrations/rails/active_job.rb +52 -20
- data/lib/raven/integrations/rails/backtrace_cleaner.rb +29 -0
- data/lib/raven/integrations/rails/controller_transaction.rb +13 -0
- data/lib/raven/integrations/rails/overrides/debug_exceptions_catcher.rb +2 -2
- data/lib/raven/integrations/rails.rb +24 -8
- data/lib/raven/integrations/rake.rb +6 -1
- data/lib/raven/integrations/sidekiq/cleanup_middleware.rb +13 -0
- data/lib/raven/integrations/sidekiq/error_handler.rb +38 -0
- data/lib/raven/integrations/sidekiq.rb +6 -57
- data/lib/raven/interface.rb +2 -2
- data/lib/raven/interfaces/exception.rb +0 -2
- data/lib/raven/interfaces/http.rb +0 -2
- data/lib/raven/interfaces/message.rb +1 -1
- data/lib/raven/interfaces/single_exception.rb +0 -2
- data/lib/raven/interfaces/stack_trace.rb +19 -27
- data/lib/raven/linecache.rb +34 -17
- data/lib/raven/logger.rb +11 -18
- data/lib/raven/processor/cookies.rb +27 -7
- data/lib/raven/processor/http_headers.rb +18 -5
- data/lib/raven/processor/post_data.rb +16 -3
- data/lib/raven/processor/removecircularreferences.rb +12 -8
- data/lib/raven/processor/removestacktrace.rb +17 -6
- data/lib/raven/processor/sanitizedata.rb +88 -29
- data/lib/raven/processor/utf8conversion.rb +39 -14
- data/lib/raven/processor.rb +1 -1
- data/lib/raven/transports/http.rb +29 -21
- data/lib/raven/transports/stdout.rb +20 -0
- data/lib/raven/transports.rb +4 -8
- data/lib/raven/utils/context_filter.rb +42 -0
- data/lib/raven/utils/deep_merge.rb +6 -12
- data/lib/raven/utils/exception_cause_chain.rb +20 -0
- data/lib/raven/utils/real_ip.rb +1 -1
- data/lib/raven/utils/request_id.rb +16 -0
- data/lib/raven/version.rb +2 -2
- data/lib/sentry-raven-without-integrations.rb +6 -1
- data/lib/sentry_raven_without_integrations.rb +1 -0
- data/sentry-raven.gemspec +28 -0
- metadata +37 -103
- 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
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
@
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
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
|
-
|
75
|
-
|
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
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
-
|
136
|
-
|
137
|
-
|
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
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
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
|
-
|
157
|
-
|
158
|
-
|
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
|
-
|
165
|
-
|
166
|
-
|
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
|
-
|
197
|
-
|
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
|
-
|
220
|
-
|
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
|
225
|
-
|
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
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
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
|
279
|
-
|
280
|
-
|
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
|
287
|
-
|
288
|
-
|
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
|
292
|
-
|
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
|