sentry-ruby 0.1.1 → 4.0.0
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 +4 -4
- data/.craft.yml +1 -0
- data/CHANGELOG.md +25 -0
- data/Gemfile +5 -0
- data/README.md +197 -21
- data/Rakefile +3 -1
- data/lib/{sentry.rb → sentry-ruby.rb} +29 -3
- data/lib/sentry/benchmarks/benchmark_transport.rb +14 -0
- data/lib/sentry/breadcrumb.rb +7 -7
- data/lib/sentry/breadcrumb/sentry_logger.rb +10 -26
- data/lib/sentry/breadcrumb_buffer.rb +2 -5
- data/lib/sentry/client.rb +32 -37
- data/lib/sentry/configuration.rb +77 -91
- data/lib/sentry/dsn.rb +6 -3
- data/lib/sentry/event.rb +42 -40
- data/lib/sentry/hub.rb +13 -2
- data/lib/sentry/interfaces/request.rb +1 -10
- data/lib/sentry/rack.rb +1 -0
- data/lib/sentry/rack/tracing.rb +39 -0
- data/lib/sentry/scope.rb +26 -4
- data/lib/sentry/span.rb +155 -0
- data/lib/sentry/transaction.rb +113 -0
- data/lib/sentry/transaction_event.rb +29 -0
- data/lib/sentry/transport.rb +11 -24
- data/lib/sentry/transport/configuration.rb +1 -8
- data/lib/sentry/transport/http_transport.rb +5 -2
- data/lib/sentry/transport/state.rb +2 -2
- data/lib/sentry/utils/request_id.rb +16 -0
- data/lib/sentry/version.rb +1 -1
- metadata +9 -6
- data/lib/sentry/event/options.rb +0 -31
- data/lib/sentry/ruby.rb +0 -1
- data/lib/sentry/utils/deep_merge.rb +0 -22
@@ -10,11 +10,8 @@ module Sentry
|
|
10
10
|
@buffer = Array.new(size)
|
11
11
|
end
|
12
12
|
|
13
|
-
def record(crumb
|
14
|
-
if block_given?
|
15
|
-
crumb = Breadcrumb.new if crumb.nil?
|
16
|
-
yield(crumb)
|
17
|
-
end
|
13
|
+
def record(crumb)
|
14
|
+
yield(crumb) if block_given?
|
18
15
|
@buffer.slice!(0)
|
19
16
|
@buffer << crumb
|
20
17
|
end
|
data/lib/sentry/client.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require "sentry/transport"
|
2
|
-
require 'sentry/utils/deep_merge'
|
3
2
|
|
4
3
|
module Sentry
|
5
4
|
class Client
|
@@ -21,55 +20,51 @@ module Sentry
|
|
21
20
|
end
|
22
21
|
end
|
23
22
|
|
24
|
-
def
|
25
|
-
event
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
23
|
+
def capture_event(event, scope, hint = nil)
|
24
|
+
scope.apply_to_event(event, hint)
|
25
|
+
|
26
|
+
if configuration.async?
|
27
|
+
begin
|
28
|
+
# We have to convert to a JSON-like hash, because background job
|
29
|
+
# processors (esp ActiveJob) may not like weird types in the event hash
|
30
|
+
configuration.async.call(event.to_json_compatible)
|
31
|
+
rescue => e
|
32
|
+
configuration.logger.error(LOGGER_PROGNAME) { "async event sending failed: #{e.message}" }
|
33
|
+
send_event(event, hint)
|
34
|
+
end
|
35
|
+
else
|
36
|
+
send_event(event, hint)
|
37
|
+
end
|
37
38
|
|
38
|
-
def capture_event(event, scope)
|
39
|
-
scope.apply_to_event(event)
|
40
|
-
send_event(event)
|
41
39
|
event
|
42
40
|
end
|
43
41
|
|
44
|
-
def event_from_exception(exception
|
45
|
-
exception_context =
|
46
|
-
if exception.instance_variable_defined?(:@__sentry_context)
|
47
|
-
exception.instance_variable_get(:@__sentry_context)
|
48
|
-
elsif exception.respond_to?(:sentry_context)
|
49
|
-
exception.sentry_context
|
50
|
-
else
|
51
|
-
{}
|
52
|
-
end
|
53
|
-
|
54
|
-
options = Utils::DeepMergeHash.deep_merge(exception_context, options)
|
55
|
-
|
42
|
+
def event_from_exception(exception)
|
56
43
|
return unless @configuration.exception_class_allowed?(exception)
|
57
44
|
|
58
|
-
|
59
|
-
|
60
|
-
Event.new(configuration: configuration, options: options).tap do |event|
|
45
|
+
Event.new(configuration: configuration).tap do |event|
|
61
46
|
event.add_exception_interface(exception)
|
62
47
|
end
|
63
48
|
end
|
64
49
|
|
65
|
-
def event_from_message(message
|
66
|
-
|
67
|
-
|
68
|
-
|
50
|
+
def event_from_message(message)
|
51
|
+
Event.new(configuration: configuration, message: message)
|
52
|
+
end
|
53
|
+
|
54
|
+
def event_from_transaction(transaction)
|
55
|
+
TransactionEvent.new(configuration: configuration).tap do |event|
|
56
|
+
event.transaction = transaction.name
|
57
|
+
event.contexts.merge!(trace: transaction.get_trace_context)
|
58
|
+
event.timestamp = transaction.timestamp
|
59
|
+
event.start_timestamp = transaction.start_timestamp
|
60
|
+
|
61
|
+
finished_spans = transaction.span_recorder.spans.select { |span| span.timestamp && span != transaction }
|
62
|
+
event.spans = finished_spans.map(&:to_hash)
|
63
|
+
end
|
69
64
|
end
|
70
65
|
|
71
66
|
def send_event(event, hint = nil)
|
72
|
-
return false unless configuration.sending_allowed?
|
67
|
+
return false unless configuration.sending_allowed?
|
73
68
|
|
74
69
|
event = configuration.before_send.call(event, hint) if configuration.before_send
|
75
70
|
if event.nil?
|
data/lib/sentry/configuration.rb
CHANGED
@@ -15,6 +15,28 @@ module Sentry
|
|
15
15
|
attr_reader :async
|
16
16
|
alias async? async
|
17
17
|
|
18
|
+
# a proc/lambda that takes an array of stack traces
|
19
|
+
# it'll be used to silence (reduce) backtrace of the exception
|
20
|
+
#
|
21
|
+
# for example:
|
22
|
+
#
|
23
|
+
# ```ruby
|
24
|
+
# Sentry.configuration.backtrace_cleanup_callback = lambda do |backtrace|
|
25
|
+
# Rails.backtrace_cleaner.clean(backtrace)
|
26
|
+
# end
|
27
|
+
# ```
|
28
|
+
#
|
29
|
+
attr_accessor :backtrace_cleanup_callback
|
30
|
+
|
31
|
+
# Optional Proc, called before sending an event to the server/
|
32
|
+
# E.g.: lambda { |event| event }
|
33
|
+
# E.g.: lambda { |event| nil }
|
34
|
+
# E.g.: lambda { |event|
|
35
|
+
# event[:message] = 'a'
|
36
|
+
# event
|
37
|
+
# }
|
38
|
+
attr_reader :before_send
|
39
|
+
|
18
40
|
# An array of breadcrumbs loggers to be used. Available options are:
|
19
41
|
# - :sentry_logger
|
20
42
|
# - :active_support_logger
|
@@ -24,10 +46,13 @@ module Sentry
|
|
24
46
|
attr_accessor :context_lines
|
25
47
|
|
26
48
|
# RACK_ENV by default.
|
27
|
-
attr_reader :
|
49
|
+
attr_reader :environment
|
28
50
|
|
29
|
-
#
|
30
|
-
|
51
|
+
# the dsn value, whether it's set via `config.dsn=` or `ENV["SENTRY_DSN"]`
|
52
|
+
attr_reader :dsn
|
53
|
+
|
54
|
+
# Whitelist of enabled_environments that will send notifications to Sentry. Array of Strings.
|
55
|
+
attr_accessor :enabled_environments
|
31
56
|
|
32
57
|
# Logger 'progname's to exclude from breadcrumbs
|
33
58
|
attr_accessor :exclude_loggers
|
@@ -64,54 +89,36 @@ module Sentry
|
|
64
89
|
# any events, and a value of 1.0 will send 100% of events.
|
65
90
|
attr_accessor :sample_rate
|
66
91
|
|
67
|
-
# a proc/lambda that takes an array of stack traces
|
68
|
-
# it'll be used to silence (reduce) backtrace of the exception
|
69
|
-
#
|
70
|
-
# for example:
|
71
|
-
#
|
72
|
-
# ```ruby
|
73
|
-
# Sentry.configuration.backtrace_cleanup_callback = lambda do |backtrace|
|
74
|
-
# Rails.backtrace_cleaner.clean(backtrace)
|
75
|
-
# end
|
76
|
-
# ```
|
77
|
-
#
|
78
|
-
attr_accessor :backtrace_cleanup_callback
|
79
|
-
|
80
92
|
# Include module versions in reports - boolean.
|
81
93
|
attr_accessor :send_modules
|
82
94
|
|
95
|
+
# When send_default_pii's value is false (default), sensitive information like
|
96
|
+
# - user ip
|
97
|
+
# - user cookie
|
98
|
+
# - request body
|
99
|
+
# will not be sent to Sentry.
|
83
100
|
attr_accessor :send_default_pii
|
84
101
|
|
85
102
|
attr_accessor :server_name
|
86
103
|
|
87
|
-
#
|
88
|
-
# Note that the object passed into the block will be a String (messages) or
|
89
|
-
# an exception.
|
90
|
-
# e.g. lambda { |exc_or_msg| exc_or_msg.some_attr == false }
|
91
|
-
attr_reader :should_capture
|
92
|
-
|
93
|
-
# Silences ready message when true.
|
94
|
-
attr_accessor :silence_ready
|
95
|
-
|
96
|
-
# Default tags for events. Hash.
|
97
|
-
attr_accessor :tags
|
98
|
-
|
104
|
+
# Return a Transport::Configuration object for transport-related configurations.
|
99
105
|
attr_reader :transport
|
100
106
|
|
101
|
-
#
|
102
|
-
|
103
|
-
# E.g.: lambda { |event, hint| nil }
|
104
|
-
# E.g.: lambda { |event, hint|
|
105
|
-
# event[:message] = 'a'
|
106
|
-
# event
|
107
|
-
# }
|
108
|
-
attr_reader :before_send
|
107
|
+
# Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
|
108
|
+
attr_accessor :traces_sample_rate
|
109
109
|
|
110
|
-
#
|
111
|
-
|
110
|
+
# Take a Proc that controls the sample rate for every tracing event, e.g.
|
111
|
+
# ```
|
112
|
+
# lambda do |tracing_context|
|
113
|
+
# # tracing_context[:transaction_context] contains the information about the transaction
|
114
|
+
# # tracing_context[:parent_sampled] contains the transaction's parent's sample decision
|
115
|
+
# true # return value can be a boolean or a float between 0.0 and 1.0
|
116
|
+
# end
|
117
|
+
# ```
|
118
|
+
attr_accessor :traces_sampler
|
112
119
|
|
113
|
-
#
|
114
|
-
attr_reader :
|
120
|
+
# these are not config options
|
121
|
+
attr_reader :errors, :gem_specs
|
115
122
|
|
116
123
|
# Most of these errors generate 4XX responses. In general, Sentry clients
|
117
124
|
# only automatically report 5xx responses.
|
@@ -141,8 +148,8 @@ module Sentry
|
|
141
148
|
self.async = false
|
142
149
|
self.breadcrumbs_logger = []
|
143
150
|
self.context_lines = 3
|
144
|
-
self.
|
145
|
-
self.
|
151
|
+
self.environment = environment_from_env
|
152
|
+
self.enabled_environments = []
|
146
153
|
self.exclude_loggers = []
|
147
154
|
self.excluded_exceptions = IGNORE_DEFAULT.dup
|
148
155
|
self.inspect_exception_causes_for_exclusion = false
|
@@ -156,11 +163,12 @@ module Sentry
|
|
156
163
|
self.send_default_pii = false
|
157
164
|
self.dsn = ENV['SENTRY_DSN']
|
158
165
|
self.server_name = server_name_from_env
|
159
|
-
|
160
|
-
self.tags = {}
|
161
|
-
@transport = Transport::Configuration.new
|
166
|
+
|
162
167
|
self.before_send = false
|
163
168
|
self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
|
169
|
+
|
170
|
+
@transport = Transport::Configuration.new
|
171
|
+
@gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
164
172
|
post_initialization_callback
|
165
173
|
end
|
166
174
|
|
@@ -198,14 +206,6 @@ module Sentry
|
|
198
206
|
@breadcrumbs_logger = logger
|
199
207
|
end
|
200
208
|
|
201
|
-
def should_capture=(value)
|
202
|
-
unless value == false || value.respond_to?(:call)
|
203
|
-
raise ArgumentError, "should_capture must be callable (or false to disable)"
|
204
|
-
end
|
205
|
-
|
206
|
-
@should_capture = value
|
207
|
-
end
|
208
|
-
|
209
209
|
def before_send=(value)
|
210
210
|
unless value == false || value.respond_to?(:call)
|
211
211
|
raise ArgumentError, "before_send must be callable (or false to disable)"
|
@@ -214,31 +214,21 @@ module Sentry
|
|
214
214
|
@before_send = value
|
215
215
|
end
|
216
216
|
|
217
|
-
|
218
|
-
|
219
|
-
# @param [Symbol] option Key for a given attribute
|
220
|
-
def [](option)
|
221
|
-
public_send(option)
|
217
|
+
def environment=(environment)
|
218
|
+
@environment = environment.to_s
|
222
219
|
end
|
223
220
|
|
224
|
-
def
|
225
|
-
@current_environment = environment.to_s
|
226
|
-
end
|
227
|
-
|
228
|
-
def capture_allowed?(message_or_exc = nil)
|
221
|
+
def sending_allowed?
|
229
222
|
@errors = []
|
230
223
|
|
231
224
|
valid? &&
|
232
|
-
|
233
|
-
capture_allowed_by_callback?(message_or_exc) &&
|
225
|
+
capture_in_environment? &&
|
234
226
|
sample_allowed?
|
235
227
|
end
|
236
|
-
# If we cannot capture, we cannot send.
|
237
|
-
alias sending_allowed? capture_allowed?
|
238
228
|
|
239
229
|
def error_messages
|
240
|
-
@errors = [errors[0]] + errors[1..-1].map(&:downcase) # fix case of all but first
|
241
|
-
errors.join(", ")
|
230
|
+
@errors = [@errors[0]] + @errors[1..-1].map(&:downcase) # fix case of all but first
|
231
|
+
@errors.join(", ")
|
242
232
|
end
|
243
233
|
|
244
234
|
def project_root=(root_dir)
|
@@ -259,7 +249,11 @@ module Sentry
|
|
259
249
|
end
|
260
250
|
|
261
251
|
def enabled_in_current_env?
|
262
|
-
|
252
|
+
enabled_environments.empty? || enabled_environments.include?(environment)
|
253
|
+
end
|
254
|
+
|
255
|
+
def tracing_enabled?
|
256
|
+
!!((@traces_sample_rate && @traces_sample_rate > 0.0) || @traces_sampler)
|
263
257
|
end
|
264
258
|
|
265
259
|
private
|
@@ -282,13 +276,17 @@ module Sentry
|
|
282
276
|
end
|
283
277
|
|
284
278
|
def excluded_exception?(incoming_exception)
|
285
|
-
|
286
|
-
matches_exception?(
|
279
|
+
excluded_exception_classes.any? do |excluded_exception|
|
280
|
+
matches_exception?(excluded_exception, incoming_exception)
|
287
281
|
end
|
288
282
|
end
|
289
283
|
|
284
|
+
def excluded_exception_classes
|
285
|
+
@excluded_exception_classes ||= excluded_exceptions.map { |e| get_exception_class(e) }
|
286
|
+
end
|
287
|
+
|
290
288
|
def get_exception_class(x)
|
291
|
-
x.is_a?(Module) ? x :
|
289
|
+
x.is_a?(Module) ? x : safe_const_get(x)
|
292
290
|
end
|
293
291
|
|
294
292
|
def matches_exception?(excluded_exception_class, incoming_exception)
|
@@ -299,14 +297,9 @@ module Sentry
|
|
299
297
|
end
|
300
298
|
end
|
301
299
|
|
302
|
-
|
303
|
-
|
304
|
-
x
|
305
|
-
if !x.match(/::/)
|
306
|
-
Object.const_get(x)
|
307
|
-
else
|
308
|
-
x.split(MODULE_SEPARATOR).reject(&:empty?).inject(Object) { |a, e| a.const_get(e) }
|
309
|
-
end
|
300
|
+
def safe_const_get(x)
|
301
|
+
x = x.to_s unless x.is_a?(String)
|
302
|
+
Object.const_get(x)
|
310
303
|
rescue NameError # There's no way to safely ask if a constant exist for an unknown string
|
311
304
|
nil
|
312
305
|
end
|
@@ -342,17 +335,10 @@ module Sentry
|
|
342
335
|
ENV['SENTRY_RELEASE']
|
343
336
|
end
|
344
337
|
|
345
|
-
def
|
338
|
+
def capture_in_environment?
|
346
339
|
return true if enabled_in_current_env?
|
347
340
|
|
348
|
-
@errors << "Not configured to send/capture in environment '#{
|
349
|
-
false
|
350
|
-
end
|
351
|
-
|
352
|
-
def capture_allowed_by_callback?(message_or_exc)
|
353
|
-
return true if !should_capture || message_or_exc.nil? || should_capture.call(message_or_exc)
|
354
|
-
|
355
|
-
@errors << "should_capture returned false"
|
341
|
+
@errors << "Not configured to send/capture in environment '#{environment}'"
|
356
342
|
false
|
357
343
|
end
|
358
344
|
|
@@ -383,7 +369,7 @@ module Sentry
|
|
383
369
|
Socket.gethostbyname(hostname).first rescue server_name
|
384
370
|
end
|
385
371
|
|
386
|
-
def
|
372
|
+
def environment_from_env
|
387
373
|
ENV['SENTRY_CURRENT_ENV'] || ENV['SENTRY_ENVIRONMENT'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'default'
|
388
374
|
end
|
389
375
|
|
data/lib/sentry/dsn.rb
CHANGED
@@ -2,7 +2,10 @@ require "uri"
|
|
2
2
|
|
3
3
|
module Sentry
|
4
4
|
class DSN
|
5
|
-
|
5
|
+
PORT_MAP = { 'http' => 80, 'https' => 443 }.freeze
|
6
|
+
REQUIRED_ATTRIBUTES = %w(host path public_key project_id).freeze
|
7
|
+
|
8
|
+
attr_reader :scheme, :secret_key, :port, *REQUIRED_ATTRIBUTES
|
6
9
|
|
7
10
|
def initialize(dsn_string)
|
8
11
|
@raw_value = dsn_string
|
@@ -24,7 +27,7 @@ module Sentry
|
|
24
27
|
end
|
25
28
|
|
26
29
|
def valid?
|
27
|
-
|
30
|
+
REQUIRED_ATTRIBUTES.all? { |k| public_send(k) }
|
28
31
|
end
|
29
32
|
|
30
33
|
def to_s
|
@@ -33,7 +36,7 @@ module Sentry
|
|
33
36
|
|
34
37
|
def server
|
35
38
|
server = "#{scheme}://#{host}"
|
36
|
-
server += ":#{port}" unless port ==
|
39
|
+
server += ":#{port}" unless port == PORT_MAP[scheme]
|
37
40
|
server += path
|
38
41
|
server
|
39
42
|
end
|
data/lib/sentry/event.rb
CHANGED
@@ -2,11 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'socket'
|
4
4
|
require 'securerandom'
|
5
|
-
require 'sentry/event/options'
|
6
5
|
require 'sentry/interface'
|
7
6
|
require 'sentry/backtrace'
|
8
|
-
require 'sentry/utils/deep_merge'
|
9
7
|
require 'sentry/utils/real_ip'
|
8
|
+
require 'sentry/utils/request_id'
|
10
9
|
|
11
10
|
module Sentry
|
12
11
|
class Event
|
@@ -15,52 +14,44 @@ module Sentry
|
|
15
14
|
release environment server_name modules
|
16
15
|
message user tags contexts extra
|
17
16
|
fingerprint breadcrumbs backtrace transaction
|
18
|
-
platform sdk
|
17
|
+
platform sdk type
|
19
18
|
)
|
20
19
|
|
21
20
|
attr_accessor(*ATTRIBUTES)
|
22
|
-
attr_reader :
|
21
|
+
attr_reader :configuration
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
def initialize(options:, configuration:)
|
23
|
+
def initialize(configuration:, message: nil)
|
27
24
|
# this needs to go first because some setters rely on configuration
|
28
25
|
@configuration = configuration
|
29
26
|
|
30
27
|
# Set some simple default values
|
31
|
-
@
|
32
|
-
@timestamp =
|
28
|
+
@event_id = SecureRandom.uuid.delete("-")
|
29
|
+
@timestamp = Sentry.utc_now.iso8601
|
33
30
|
@platform = :ruby
|
34
31
|
@sdk = Sentry.sdk_meta
|
35
32
|
|
36
|
-
@user =
|
37
|
-
@extra =
|
38
|
-
@contexts =
|
39
|
-
@tags =
|
40
|
-
|
41
|
-
@fingerprint = options.fingerprint
|
33
|
+
@user = {}
|
34
|
+
@extra = {}
|
35
|
+
@contexts = {}
|
36
|
+
@tags = {}
|
42
37
|
|
43
|
-
@
|
44
|
-
@environment = options.environment || configuration.current_environment
|
45
|
-
@release = options.release || configuration.release
|
46
|
-
@modules = list_gem_specs if configuration.send_modules
|
38
|
+
@fingerprint = []
|
47
39
|
|
48
|
-
@
|
40
|
+
@server_name = configuration.server_name
|
41
|
+
@environment = configuration.environment
|
42
|
+
@release = configuration.release
|
43
|
+
@modules = configuration.gem_specs if configuration.send_modules
|
49
44
|
|
50
|
-
|
45
|
+
@message = message || ""
|
51
46
|
|
52
|
-
|
53
|
-
@stacktrace = Sentry::StacktraceInterface.new.tap do |int|
|
54
|
-
int.frames = stacktrace_interface_from(options.backtrace)
|
55
|
-
end
|
56
|
-
end
|
47
|
+
self.level = :error
|
57
48
|
end
|
58
49
|
|
59
50
|
class << self
|
60
51
|
def get_log_message(event_hash)
|
61
52
|
message = event_hash[:message] || event_hash['message']
|
62
|
-
message = get_message_from_exception(event_hash) if message.empty?
|
63
|
-
message = '<no message value>' if message.empty?
|
53
|
+
message = get_message_from_exception(event_hash) if message.nil? || message.empty?
|
54
|
+
message = '<no message value>' if message.nil? || message.empty?
|
64
55
|
message
|
65
56
|
end
|
66
57
|
|
@@ -76,7 +67,7 @@ module Sentry
|
|
76
67
|
end
|
77
68
|
|
78
69
|
def timestamp=(time)
|
79
|
-
@timestamp = time.is_a?(Time) ? time.
|
70
|
+
@timestamp = time.is_a?(Time) ? time.to_f : time
|
80
71
|
end
|
81
72
|
|
82
73
|
def level=(new_level) # needed to meet the Sentry spec
|
@@ -92,14 +83,18 @@ module Sentry
|
|
92
83
|
if configuration.send_default_pii && ip = calculate_real_ip_from_rack(env.dup)
|
93
84
|
user[:ip_address] = ip
|
94
85
|
end
|
86
|
+
if request_id = Utils::RequestId.read_from(env)
|
87
|
+
tags[:request_id] = request_id
|
88
|
+
end
|
95
89
|
end
|
96
90
|
end
|
97
91
|
|
98
|
-
def
|
99
|
-
|
100
|
-
|
101
|
-
end
|
92
|
+
def type
|
93
|
+
"event"
|
94
|
+
end
|
102
95
|
|
96
|
+
def to_hash
|
97
|
+
data = serialize_attributes
|
103
98
|
data[:breadcrumbs] = breadcrumbs.to_hash if breadcrumbs
|
104
99
|
data[:stacktrace] = @stacktrace.to_hash if @stacktrace
|
105
100
|
data[:request] = @request.to_hash if @request
|
@@ -113,6 +108,10 @@ module Sentry
|
|
113
108
|
end
|
114
109
|
|
115
110
|
def add_exception_interface(exc)
|
111
|
+
if exc.respond_to?(:sentry_context)
|
112
|
+
@extra.merge!(exc.sentry_context)
|
113
|
+
end
|
114
|
+
|
116
115
|
@exception = Sentry::ExceptionInterface.new.tap do |exc_int|
|
117
116
|
exceptions = Sentry::Utils::ExceptionCauseChain.exception_to_array(exc).reverse
|
118
117
|
backtraces = Set.new
|
@@ -145,9 +144,9 @@ module Sentry
|
|
145
144
|
frame.in_app = line.in_app
|
146
145
|
frame.module = line.module_name if line.module_name
|
147
146
|
|
148
|
-
if configuration
|
147
|
+
if configuration.context_lines && frame.abs_path
|
149
148
|
frame.pre_context, frame.context_line, frame.post_context = \
|
150
|
-
configuration.linecache.get_file_context(frame.abs_path, frame.lineno, configuration
|
149
|
+
configuration.linecache.get_file_context(frame.abs_path, frame.lineno, configuration.context_lines)
|
151
150
|
end
|
152
151
|
|
153
152
|
memo << frame if frame.filename
|
@@ -156,6 +155,14 @@ module Sentry
|
|
156
155
|
|
157
156
|
private
|
158
157
|
|
158
|
+
def serialize_attributes
|
159
|
+
self.class::ATTRIBUTES.each_with_object({}) do |att, memo|
|
160
|
+
if value = public_send(att)
|
161
|
+
memo[att] = value
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
159
166
|
# When behind a proxy (or if the user is using a proxy), we can't use
|
160
167
|
# REMOTE_ADDR to determine the Event IP, and must use other headers instead.
|
161
168
|
def calculate_real_ip_from_rack(env)
|
@@ -166,10 +173,5 @@ module Sentry
|
|
166
173
|
:forwarded_for => env["HTTP_X_FORWARDED_FOR"]
|
167
174
|
).calculate_ip
|
168
175
|
end
|
169
|
-
|
170
|
-
def list_gem_specs
|
171
|
-
# Older versions of Rubygems don't support iterating over all specs
|
172
|
-
Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
173
|
-
end
|
174
176
|
end
|
175
177
|
end
|