sentry-ruby 5.10.0 → 5.26.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/.rspec +3 -1
- data/Gemfile +12 -13
- data/README.md +26 -11
- data/Rakefile +9 -11
- data/bin/console +2 -0
- data/lib/sentry/attachment.rb +40 -0
- data/lib/sentry/background_worker.rb +11 -5
- data/lib/sentry/backpressure_monitor.rb +45 -0
- data/lib/sentry/backtrace.rb +12 -9
- data/lib/sentry/baggage.rb +7 -7
- data/lib/sentry/breadcrumb/sentry_logger.rb +6 -6
- data/lib/sentry/breadcrumb.rb +13 -6
- data/lib/sentry/check_in_event.rb +61 -0
- data/lib/sentry/client.rb +214 -25
- data/lib/sentry/configuration.rb +221 -38
- data/lib/sentry/core_ext/object/deep_dup.rb +1 -1
- data/lib/sentry/cron/configuration.rb +23 -0
- data/lib/sentry/cron/monitor_check_ins.rb +77 -0
- data/lib/sentry/cron/monitor_config.rb +53 -0
- data/lib/sentry/cron/monitor_schedule.rb +42 -0
- data/lib/sentry/dsn.rb +4 -4
- data/lib/sentry/envelope/item.rb +88 -0
- data/lib/sentry/envelope.rb +2 -68
- data/lib/sentry/error_event.rb +2 -2
- data/lib/sentry/event.rb +28 -47
- data/lib/sentry/excon/middleware.rb +77 -0
- data/lib/sentry/excon.rb +10 -0
- data/lib/sentry/faraday.rb +77 -0
- data/lib/sentry/graphql.rb +9 -0
- data/lib/sentry/hub.rb +138 -6
- data/lib/sentry/integrable.rb +10 -0
- data/lib/sentry/interface.rb +1 -0
- data/lib/sentry/interfaces/exception.rb +5 -3
- data/lib/sentry/interfaces/mechanism.rb +20 -0
- data/lib/sentry/interfaces/request.rb +8 -8
- data/lib/sentry/interfaces/single_exception.rb +13 -9
- data/lib/sentry/interfaces/stacktrace.rb +3 -1
- data/lib/sentry/interfaces/stacktrace_builder.rb +23 -2
- data/lib/sentry/linecache.rb +3 -3
- data/lib/sentry/log_event.rb +206 -0
- data/lib/sentry/log_event_buffer.rb +75 -0
- data/lib/sentry/logger.rb +1 -1
- data/lib/sentry/metrics/aggregator.rb +248 -0
- data/lib/sentry/metrics/configuration.rb +47 -0
- data/lib/sentry/metrics/counter_metric.rb +25 -0
- data/lib/sentry/metrics/distribution_metric.rb +25 -0
- data/lib/sentry/metrics/gauge_metric.rb +35 -0
- data/lib/sentry/metrics/local_aggregator.rb +53 -0
- data/lib/sentry/metrics/metric.rb +19 -0
- data/lib/sentry/metrics/set_metric.rb +28 -0
- data/lib/sentry/metrics/timing.rb +51 -0
- data/lib/sentry/metrics.rb +56 -0
- data/lib/sentry/net/http.rb +27 -44
- data/lib/sentry/profiler/helpers.rb +46 -0
- data/lib/sentry/profiler.rb +41 -60
- data/lib/sentry/propagation_context.rb +135 -0
- data/lib/sentry/puma.rb +12 -5
- data/lib/sentry/rack/capture_exceptions.rb +17 -8
- data/lib/sentry/rack.rb +2 -2
- data/lib/sentry/rake.rb +4 -15
- data/lib/sentry/redis.rb +10 -4
- data/lib/sentry/release_detector.rb +5 -5
- data/lib/sentry/rspec.rb +91 -0
- data/lib/sentry/scope.rb +75 -39
- data/lib/sentry/session.rb +2 -2
- data/lib/sentry/session_flusher.rb +15 -43
- data/lib/sentry/span.rb +92 -8
- data/lib/sentry/std_lib_logger.rb +50 -0
- data/lib/sentry/structured_logger.rb +138 -0
- data/lib/sentry/test_helper.rb +42 -13
- data/lib/sentry/threaded_periodic_worker.rb +39 -0
- data/lib/sentry/transaction.rb +44 -43
- data/lib/sentry/transaction_event.rb +10 -6
- data/lib/sentry/transport/configuration.rb +73 -1
- data/lib/sentry/transport/http_transport.rb +71 -41
- data/lib/sentry/transport/spotlight_transport.rb +50 -0
- data/lib/sentry/transport.rb +53 -49
- data/lib/sentry/utils/argument_checking_helper.rb +12 -0
- data/lib/sentry/utils/env_helper.rb +21 -0
- data/lib/sentry/utils/http_tracing.rb +74 -0
- data/lib/sentry/utils/logging_helper.rb +10 -7
- data/lib/sentry/utils/real_ip.rb +2 -2
- data/lib/sentry/utils/request_id.rb +1 -1
- data/lib/sentry/utils/uuid.rb +13 -0
- data/lib/sentry/vernier/output.rb +89 -0
- data/lib/sentry/vernier/profiler.rb +132 -0
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +206 -35
- data/sentry-ruby-core.gemspec +3 -1
- data/sentry-ruby.gemspec +15 -6
- metadata +61 -11
data/lib/sentry/hub.rb
CHANGED
@@ -8,12 +8,42 @@ module Sentry
|
|
8
8
|
class Hub
|
9
9
|
include ArgumentCheckingHelper
|
10
10
|
|
11
|
+
MUTEX = Mutex.new
|
12
|
+
|
11
13
|
attr_reader :last_event_id
|
12
14
|
|
15
|
+
attr_reader :current_profiler
|
16
|
+
|
13
17
|
def initialize(client, scope)
|
14
18
|
first_layer = Layer.new(client, scope)
|
15
19
|
@stack = [first_layer]
|
16
20
|
@last_event_id = nil
|
21
|
+
@current_profiler = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
# This is an internal private method
|
25
|
+
# @api private
|
26
|
+
def start_profiler!(transaction)
|
27
|
+
MUTEX.synchronize do
|
28
|
+
transaction.start_profiler!
|
29
|
+
@current_profiler[transaction.__id__] = transaction.profiler
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# This is an internal private method
|
34
|
+
# @api private
|
35
|
+
def stop_profiler!(transaction)
|
36
|
+
MUTEX.synchronize do
|
37
|
+
@current_profiler.delete(transaction.__id__)&.stop
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# This is an internal private method
|
42
|
+
# @api private
|
43
|
+
def profiler_running?
|
44
|
+
MUTEX.synchronize do
|
45
|
+
!@current_profiler.empty?
|
46
|
+
end
|
17
47
|
end
|
18
48
|
|
19
49
|
def new_from_top
|
@@ -73,7 +103,13 @@ module Sentry
|
|
73
103
|
end
|
74
104
|
|
75
105
|
def pop_scope
|
76
|
-
@stack.
|
106
|
+
if @stack.size > 1
|
107
|
+
@stack.pop
|
108
|
+
else
|
109
|
+
# We never want to enter a situation where we have no scope and no client
|
110
|
+
client = current_client
|
111
|
+
@stack = [Layer.new(client, Scope.new)]
|
112
|
+
end
|
77
113
|
end
|
78
114
|
|
79
115
|
def start_transaction(transaction: nil, custom_sampling_context: {}, instrumenter: :sentry, **options)
|
@@ -90,7 +126,7 @@ module Sentry
|
|
90
126
|
sampling_context.merge!(custom_sampling_context)
|
91
127
|
transaction.set_initial_sample_decision(sampling_context: sampling_context)
|
92
128
|
|
93
|
-
|
129
|
+
start_profiler!(transaction)
|
94
130
|
|
95
131
|
transaction
|
96
132
|
end
|
@@ -156,6 +192,40 @@ module Sentry
|
|
156
192
|
capture_event(event, **options, &block)
|
157
193
|
end
|
158
194
|
|
195
|
+
def capture_check_in(slug, status, **options)
|
196
|
+
check_argument_type!(slug, ::String)
|
197
|
+
check_argument_includes!(status, Sentry::CheckInEvent::VALID_STATUSES)
|
198
|
+
|
199
|
+
return unless current_client
|
200
|
+
|
201
|
+
options[:hint] ||= {}
|
202
|
+
options[:hint][:slug] = slug
|
203
|
+
|
204
|
+
event = current_client.event_from_check_in(
|
205
|
+
slug,
|
206
|
+
status,
|
207
|
+
options[:hint],
|
208
|
+
duration: options.delete(:duration),
|
209
|
+
monitor_config: options.delete(:monitor_config),
|
210
|
+
check_in_id: options.delete(:check_in_id)
|
211
|
+
)
|
212
|
+
|
213
|
+
return unless event
|
214
|
+
|
215
|
+
capture_event(event, **options)
|
216
|
+
event.check_in_id
|
217
|
+
end
|
218
|
+
|
219
|
+
def capture_log_event(message, **options)
|
220
|
+
return unless current_client
|
221
|
+
|
222
|
+
event = current_client.event_from_log(message, **options)
|
223
|
+
|
224
|
+
return unless event
|
225
|
+
|
226
|
+
current_client.buffer_log_event(event, current_scope)
|
227
|
+
end
|
228
|
+
|
159
229
|
def capture_event(event, **options, &block)
|
160
230
|
check_argument_type!(event, Sentry::Event)
|
161
231
|
|
@@ -169,7 +239,14 @@ module Sentry
|
|
169
239
|
elsif custom_scope = options[:scope]
|
170
240
|
scope.update_from_scope(custom_scope)
|
171
241
|
elsif !options.empty?
|
172
|
-
scope.update_from_options(**options)
|
242
|
+
unsupported_option_keys = scope.update_from_options(**options)
|
243
|
+
|
244
|
+
unless unsupported_option_keys.empty?
|
245
|
+
configuration.log_debug <<~MSG
|
246
|
+
Options #{unsupported_option_keys} are not supported and will not be applied to the event.
|
247
|
+
You may want to set them under the `extra` option.
|
248
|
+
MSG
|
249
|
+
end
|
173
250
|
end
|
174
251
|
|
175
252
|
event = current_client.capture_event(event, scope, hint)
|
@@ -178,11 +255,12 @@ module Sentry
|
|
178
255
|
configuration.log_debug(event.to_json_compatible)
|
179
256
|
end
|
180
257
|
|
181
|
-
@last_event_id = event&.event_id
|
258
|
+
@last_event_id = event&.event_id if event.is_a?(Sentry::ErrorEvent)
|
182
259
|
event
|
183
260
|
end
|
184
261
|
|
185
262
|
def add_breadcrumb(breadcrumb, hint: {})
|
263
|
+
return unless current_client
|
186
264
|
return unless configuration.enabled_in_current_env?
|
187
265
|
|
188
266
|
if before_breadcrumb = current_client.configuration.before_breadcrumb
|
@@ -217,11 +295,15 @@ module Sentry
|
|
217
295
|
|
218
296
|
return unless session
|
219
297
|
session.close
|
220
|
-
|
298
|
+
|
299
|
+
# NOTE: Under some circumstances, session_flusher nilified out of sync
|
300
|
+
# See: https://github.com/getsentry/sentry-ruby/issues/2378
|
301
|
+
# See: https://github.com/getsentry/sentry-ruby/pull/2396
|
302
|
+
Sentry.session_flusher&.add_session(session)
|
221
303
|
end
|
222
304
|
|
223
305
|
def with_session_tracking(&block)
|
224
|
-
return yield unless configuration.
|
306
|
+
return yield unless configuration.session_tracking?
|
225
307
|
|
226
308
|
start_session
|
227
309
|
yield
|
@@ -229,6 +311,56 @@ module Sentry
|
|
229
311
|
end_session
|
230
312
|
end
|
231
313
|
|
314
|
+
def get_traceparent
|
315
|
+
return nil unless current_scope
|
316
|
+
|
317
|
+
current_scope.get_span&.to_sentry_trace ||
|
318
|
+
current_scope.propagation_context.get_traceparent
|
319
|
+
end
|
320
|
+
|
321
|
+
def get_baggage
|
322
|
+
return nil unless current_scope
|
323
|
+
|
324
|
+
current_scope.get_span&.to_baggage ||
|
325
|
+
current_scope.propagation_context.get_baggage&.serialize
|
326
|
+
end
|
327
|
+
|
328
|
+
def get_trace_propagation_headers
|
329
|
+
headers = {}
|
330
|
+
|
331
|
+
traceparent = get_traceparent
|
332
|
+
headers[SENTRY_TRACE_HEADER_NAME] = traceparent if traceparent
|
333
|
+
|
334
|
+
baggage = get_baggage
|
335
|
+
headers[BAGGAGE_HEADER_NAME] = baggage if baggage && !baggage.empty?
|
336
|
+
|
337
|
+
headers
|
338
|
+
end
|
339
|
+
|
340
|
+
def get_trace_propagation_meta
|
341
|
+
get_trace_propagation_headers.map do |k, v|
|
342
|
+
"<meta name=\"#{k}\" content=\"#{v}\">"
|
343
|
+
end.join("\n")
|
344
|
+
end
|
345
|
+
|
346
|
+
def continue_trace(env, **options)
|
347
|
+
configure_scope { |s| s.generate_propagation_context(env) }
|
348
|
+
|
349
|
+
return nil unless configuration.tracing_enabled?
|
350
|
+
|
351
|
+
propagation_context = current_scope.propagation_context
|
352
|
+
return nil unless propagation_context.incoming_trace
|
353
|
+
|
354
|
+
Transaction.new(
|
355
|
+
hub: self,
|
356
|
+
trace_id: propagation_context.trace_id,
|
357
|
+
parent_span_id: propagation_context.parent_span_id,
|
358
|
+
parent_sampled: propagation_context.parent_sampled,
|
359
|
+
baggage: propagation_context.baggage,
|
360
|
+
**options
|
361
|
+
)
|
362
|
+
end
|
363
|
+
|
232
364
|
private
|
233
365
|
|
234
366
|
def current_layer
|
data/lib/sentry/integrable.rb
CHANGED
@@ -14,6 +14,10 @@ module Sentry
|
|
14
14
|
def capture_exception(exception, **options, &block)
|
15
15
|
options[:hint] ||= {}
|
16
16
|
options[:hint][:integration] = integration_name
|
17
|
+
|
18
|
+
# within an integration, we usually intercept uncaught exceptions so we set handled to false.
|
19
|
+
options[:hint][:mechanism] ||= Sentry::Mechanism.new(type: integration_name, handled: false)
|
20
|
+
|
17
21
|
Sentry.capture_exception(exception, **options, &block)
|
18
22
|
end
|
19
23
|
|
@@ -22,5 +26,11 @@ module Sentry
|
|
22
26
|
options[:hint][:integration] = integration_name
|
23
27
|
Sentry.capture_message(message, **options, &block)
|
24
28
|
end
|
29
|
+
|
30
|
+
def capture_check_in(slug, status, **options, &block)
|
31
|
+
options[:hint] ||= {}
|
32
|
+
options[:hint][:integration] = integration_name
|
33
|
+
Sentry.capture_check_in(slug, status, **options, &block)
|
34
|
+
end
|
25
35
|
end
|
26
36
|
end
|
data/lib/sentry/interface.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require "set"
|
3
4
|
|
4
5
|
module Sentry
|
@@ -23,17 +24,18 @@ module Sentry
|
|
23
24
|
# @param stacktrace_builder [StacktraceBuilder]
|
24
25
|
# @see SingleExceptionInterface#build_with_stacktrace
|
25
26
|
# @see SingleExceptionInterface#initialize
|
27
|
+
# @param mechanism [Mechanism]
|
26
28
|
# @return [ExceptionInterface]
|
27
|
-
def self.build(exception:, stacktrace_builder:)
|
29
|
+
def self.build(exception:, stacktrace_builder:, mechanism:)
|
28
30
|
exceptions = Sentry::Utils::ExceptionCauseChain.exception_to_array(exception).reverse
|
29
31
|
processed_backtrace_ids = Set.new
|
30
32
|
|
31
33
|
exceptions = exceptions.map do |e|
|
32
34
|
if e.backtrace && !processed_backtrace_ids.include?(e.backtrace.object_id)
|
33
35
|
processed_backtrace_ids << e.backtrace.object_id
|
34
|
-
SingleExceptionInterface.build_with_stacktrace(exception: e, stacktrace_builder: stacktrace_builder)
|
36
|
+
SingleExceptionInterface.build_with_stacktrace(exception: e, stacktrace_builder: stacktrace_builder, mechanism: mechanism)
|
35
37
|
else
|
36
|
-
SingleExceptionInterface.new(exception: exception)
|
38
|
+
SingleExceptionInterface.new(exception: exception, mechanism: mechanism)
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
class Mechanism < Interface
|
5
|
+
# Generic identifier, mostly the source integration for this exception.
|
6
|
+
# @return [String]
|
7
|
+
attr_accessor :type
|
8
|
+
|
9
|
+
# A manually captured exception has handled set to true,
|
10
|
+
# false if coming from an integration where we intercept an uncaught exception.
|
11
|
+
# Defaults to true here and will be set to false explicitly in integrations.
|
12
|
+
# @return [Boolean]
|
13
|
+
attr_accessor :handled
|
14
|
+
|
15
|
+
def initialize(type: "generic", handled: true)
|
16
|
+
@type = type
|
17
|
+
@handled = handled
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Sentry
|
4
4
|
class RequestInterface < Interface
|
5
|
-
REQUEST_ID_HEADERS = %w
|
6
|
-
CONTENT_HEADERS = %w
|
5
|
+
REQUEST_ID_HEADERS = %w[action_dispatch.request_id HTTP_X_REQUEST_ID].freeze
|
6
|
+
CONTENT_HEADERS = %w[CONTENT_TYPE CONTENT_LENGTH].freeze
|
7
7
|
IP_HEADERS = [
|
8
8
|
"REMOTE_ADDR",
|
9
9
|
"HTTP_CLIENT_IP",
|
@@ -59,7 +59,7 @@ module Sentry
|
|
59
59
|
self.query_string = request.query_string
|
60
60
|
end
|
61
61
|
|
62
|
-
self.url = request.scheme && request.url.split(
|
62
|
+
self.url = request.scheme && request.url.split("?").first
|
63
63
|
self.method = request.request_method
|
64
64
|
|
65
65
|
self.headers = filter_and_format_headers(env, send_default_pii)
|
@@ -85,21 +85,21 @@ module Sentry
|
|
85
85
|
env.each_with_object({}) do |(key, value), memo|
|
86
86
|
begin
|
87
87
|
key = key.to_s # rack env can contain symbols
|
88
|
-
next memo[
|
88
|
+
next memo["X-Request-Id"] ||= Utils::RequestId.read_from(env) if Utils::RequestId::REQUEST_ID_HEADERS.include?(key)
|
89
89
|
next if is_server_protocol?(key, value, env["SERVER_PROTOCOL"])
|
90
90
|
next if is_skippable_header?(key)
|
91
91
|
next if key == "HTTP_AUTHORIZATION" && !send_default_pii
|
92
92
|
|
93
93
|
# Rack stores headers as HTTP_WHAT_EVER, we need What-Ever
|
94
94
|
key = key.sub(/^HTTP_/, "")
|
95
|
-
key = key.split(
|
95
|
+
key = key.split("_").map(&:capitalize).join("-")
|
96
96
|
|
97
97
|
memo[key] = Utils::EncodingHelper.encode_to_utf_8(value.to_s)
|
98
98
|
rescue StandardError => e
|
99
99
|
# Rails adds objects to the Rack env that can sometimes raise exceptions
|
100
100
|
# when `to_s` is called.
|
101
101
|
# See: https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/remote_ip.rb#L134
|
102
|
-
Sentry.
|
102
|
+
Sentry.sdk_logger.warn(LOGGER_PROGNAME) { "Error raised while formatting headers: #{e.message}" }
|
103
103
|
next
|
104
104
|
end
|
105
105
|
end
|
@@ -108,7 +108,7 @@ module Sentry
|
|
108
108
|
def is_skippable_header?(key)
|
109
109
|
key.upcase != key || # lower-case envs aren't real http headers
|
110
110
|
key == "HTTP_COOKIE" || # Cookies don't go here, they go somewhere else
|
111
|
-
!(key.start_with?(
|
111
|
+
!(key.start_with?("HTTP_") || CONTENT_HEADERS.include?(key))
|
112
112
|
end
|
113
113
|
|
114
114
|
# In versions < 3, Rack adds in an incorrect HTTP_VERSION key, which causes downstream
|
@@ -120,7 +120,7 @@ module Sentry
|
|
120
120
|
rack_version = Gem::Version.new(::Rack.release)
|
121
121
|
return false if rack_version >= Gem::Version.new("3.0")
|
122
122
|
|
123
|
-
key ==
|
123
|
+
key == "HTTP_VERSION" && value == protocol_version
|
124
124
|
end
|
125
125
|
|
126
126
|
def filter_and_format_env(env, rack_env_whitelist)
|
@@ -7,13 +7,14 @@ module Sentry
|
|
7
7
|
include CustomInspection
|
8
8
|
|
9
9
|
SKIP_INSPECTION_ATTRIBUTES = [:@stacktrace]
|
10
|
-
PROBLEMATIC_LOCAL_VALUE_REPLACEMENT = "[ignored due to error]"
|
11
|
-
OMISSION_MARK = "..."
|
10
|
+
PROBLEMATIC_LOCAL_VALUE_REPLACEMENT = "[ignored due to error]"
|
11
|
+
OMISSION_MARK = "..."
|
12
12
|
MAX_LOCAL_BYTES = 1024
|
13
13
|
|
14
|
-
attr_reader :type, :
|
14
|
+
attr_reader :type, :module, :thread_id, :stacktrace, :mechanism
|
15
|
+
attr_accessor :value
|
15
16
|
|
16
|
-
def initialize(exception:, stacktrace: nil)
|
17
|
+
def initialize(exception:, mechanism:, stacktrace: nil)
|
17
18
|
@type = exception.class.to_s
|
18
19
|
exception_message =
|
19
20
|
if exception.respond_to?(:detailed_message)
|
@@ -21,23 +22,26 @@ module Sentry
|
|
21
22
|
else
|
22
23
|
exception.message || ""
|
23
24
|
end
|
25
|
+
exception_message = exception_message.inspect unless exception_message.is_a?(String)
|
24
26
|
|
25
|
-
@value = exception_message.byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES)
|
27
|
+
@value = Utils::EncodingHelper.encode_to_utf_8(exception_message.byteslice(0..Event::MAX_MESSAGE_SIZE_IN_BYTES))
|
26
28
|
|
27
|
-
@module = exception.class.to_s.split(
|
29
|
+
@module = exception.class.to_s.split("::")[0...-1].join("::")
|
28
30
|
@thread_id = Thread.current.object_id
|
29
31
|
@stacktrace = stacktrace
|
32
|
+
@mechanism = mechanism
|
30
33
|
end
|
31
34
|
|
32
35
|
def to_hash
|
33
36
|
data = super
|
34
37
|
data[:stacktrace] = data[:stacktrace].to_hash if data[:stacktrace]
|
38
|
+
data[:mechanism] = data[:mechanism].to_hash
|
35
39
|
data
|
36
40
|
end
|
37
41
|
|
38
42
|
# patch this method if you want to change an exception's stacktrace frames
|
39
43
|
# also see `StacktraceBuilder.build`.
|
40
|
-
def self.build_with_stacktrace(exception:, stacktrace_builder:)
|
44
|
+
def self.build_with_stacktrace(exception:, stacktrace_builder:, mechanism:)
|
41
45
|
stacktrace = stacktrace_builder.build(backtrace: exception.backtrace)
|
42
46
|
|
43
47
|
if locals = exception.instance_variable_get(:@sentry_locals)
|
@@ -50,7 +54,7 @@ module Sentry
|
|
50
54
|
v = v.byteslice(0..MAX_LOCAL_BYTES - 1) + OMISSION_MARK
|
51
55
|
end
|
52
56
|
|
53
|
-
v
|
57
|
+
Utils::EncodingHelper.encode_to_utf_8(v)
|
54
58
|
rescue StandardError
|
55
59
|
PROBLEMATIC_LOCAL_VALUE_REPLACEMENT
|
56
60
|
end
|
@@ -59,7 +63,7 @@ module Sentry
|
|
59
63
|
stacktrace.frames.last.vars = locals
|
60
64
|
end
|
61
65
|
|
62
|
-
new(exception: exception, stacktrace: stacktrace)
|
66
|
+
new(exception: exception, stacktrace: stacktrace, mechanism: mechanism)
|
63
67
|
end
|
64
68
|
end
|
65
69
|
end
|
@@ -27,8 +27,9 @@ module Sentry
|
|
27
27
|
attr_accessor :abs_path, :context_line, :function, :in_app, :filename,
|
28
28
|
:lineno, :module, :pre_context, :post_context, :vars
|
29
29
|
|
30
|
-
def initialize(project_root, line)
|
30
|
+
def initialize(project_root, line, strip_backtrace_load_path = true)
|
31
31
|
@project_root = project_root
|
32
|
+
@strip_backtrace_load_path = strip_backtrace_load_path
|
32
33
|
|
33
34
|
@abs_path = line.file
|
34
35
|
@function = line.method if line.method
|
@@ -44,6 +45,7 @@ module Sentry
|
|
44
45
|
|
45
46
|
def compute_filename
|
46
47
|
return if abs_path.nil?
|
48
|
+
return abs_path unless @strip_backtrace_load_path
|
47
49
|
|
48
50
|
prefix =
|
49
51
|
if under_project_root? && in_app
|
@@ -17,22 +17,35 @@ module Sentry
|
|
17
17
|
# @return [Proc, nil]
|
18
18
|
attr_reader :backtrace_cleanup_callback
|
19
19
|
|
20
|
+
# @return [Boolean]
|
21
|
+
attr_reader :strip_backtrace_load_path
|
22
|
+
|
20
23
|
# @param project_root [String]
|
21
24
|
# @param app_dirs_pattern [Regexp, nil]
|
22
25
|
# @param linecache [LineCache]
|
23
26
|
# @param context_lines [Integer, nil]
|
24
27
|
# @param backtrace_cleanup_callback [Proc, nil]
|
28
|
+
# @param strip_backtrace_load_path [Boolean]
|
25
29
|
# @see Configuration#project_root
|
26
30
|
# @see Configuration#app_dirs_pattern
|
27
31
|
# @see Configuration#linecache
|
28
32
|
# @see Configuration#context_lines
|
29
33
|
# @see Configuration#backtrace_cleanup_callback
|
30
|
-
|
34
|
+
# @see Configuration#strip_backtrace_load_path
|
35
|
+
def initialize(
|
36
|
+
project_root:,
|
37
|
+
app_dirs_pattern:,
|
38
|
+
linecache:,
|
39
|
+
context_lines:,
|
40
|
+
backtrace_cleanup_callback: nil,
|
41
|
+
strip_backtrace_load_path: true
|
42
|
+
)
|
31
43
|
@project_root = project_root
|
32
44
|
@app_dirs_pattern = app_dirs_pattern
|
33
45
|
@linecache = linecache
|
34
46
|
@context_lines = context_lines
|
35
47
|
@backtrace_cleanup_callback = backtrace_cleanup_callback
|
48
|
+
@strip_backtrace_load_path = strip_backtrace_load_path
|
36
49
|
end
|
37
50
|
|
38
51
|
# Generates a StacktraceInterface with the given backtrace.
|
@@ -62,10 +75,18 @@ module Sentry
|
|
62
75
|
StacktraceInterface.new(frames: frames)
|
63
76
|
end
|
64
77
|
|
78
|
+
# Get the code location hash for a single line for where metrics where added.
|
79
|
+
# @return [Hash]
|
80
|
+
def metrics_code_location(unparsed_line)
|
81
|
+
parsed_line = Backtrace::Line.parse(unparsed_line)
|
82
|
+
frame = convert_parsed_line_into_frame(parsed_line)
|
83
|
+
frame.to_hash.reject { |k, _| %i[project_root in_app].include?(k) }
|
84
|
+
end
|
85
|
+
|
65
86
|
private
|
66
87
|
|
67
88
|
def convert_parsed_line_into_frame(line)
|
68
|
-
frame = StacktraceInterface::Frame.new(project_root, line)
|
89
|
+
frame = StacktraceInterface::Frame.new(project_root, line, strip_backtrace_load_path)
|
69
90
|
frame.set_context(linecache, context_lines) if context_lines
|
70
91
|
frame
|
71
92
|
end
|