sentry-ruby-core 4.8.0 → 5.2.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/.yardopts +2 -0
- data/Gemfile +3 -0
- data/README.md +2 -0
- data/lib/sentry/background_worker.rb +33 -3
- data/lib/sentry/backtrace.rb +1 -3
- data/lib/sentry/breadcrumb/sentry_logger.rb +2 -0
- data/lib/sentry/breadcrumb.rb +24 -3
- data/lib/sentry/breadcrumb_buffer.rb +16 -0
- data/lib/sentry/client.rb +38 -2
- data/lib/sentry/configuration.rb +94 -41
- data/lib/sentry/core_ext/object/deep_dup.rb +2 -0
- data/lib/sentry/core_ext/object/duplicable.rb +1 -0
- data/lib/sentry/dsn.rb +2 -0
- data/lib/sentry/envelope.rb +45 -0
- data/lib/sentry/event.rb +55 -18
- data/lib/sentry/exceptions.rb +2 -0
- data/lib/sentry/hub.rb +38 -2
- data/lib/sentry/integrable.rb +2 -0
- data/lib/sentry/interface.rb +3 -10
- data/lib/sentry/interfaces/exception.rb +14 -3
- data/lib/sentry/interfaces/request.rb +37 -20
- data/lib/sentry/interfaces/single_exception.rb +2 -0
- data/lib/sentry/interfaces/stacktrace.rb +6 -0
- data/lib/sentry/interfaces/stacktrace_builder.rb +39 -10
- data/lib/sentry/interfaces/threads.rb +12 -2
- data/lib/sentry/linecache.rb +3 -0
- data/lib/sentry/net/http.rb +54 -65
- data/lib/sentry/rack/capture_exceptions.rb +28 -24
- data/lib/sentry/rack.rb +2 -0
- data/lib/sentry/rake.rb +16 -6
- data/lib/sentry/redis.rb +90 -0
- data/lib/sentry/release_detector.rb +3 -0
- data/lib/sentry/scope.rb +85 -6
- data/lib/sentry/session.rb +35 -0
- data/lib/sentry/session_flusher.rb +79 -0
- data/lib/sentry/span.rb +84 -8
- data/lib/sentry/transaction.rb +48 -14
- data/lib/sentry/transaction_event.rb +8 -0
- data/lib/sentry/transport/configuration.rb +3 -2
- data/lib/sentry/transport/dummy_transport.rb +8 -1
- data/lib/sentry/transport/http_transport.rb +55 -42
- data/lib/sentry/transport.rb +79 -37
- data/lib/sentry/utils/argument_checking_helper.rb +2 -0
- data/lib/sentry/utils/custom_inspection.rb +2 -0
- data/lib/sentry/utils/exception_cause_chain.rb +2 -0
- data/lib/sentry/utils/logging_helper.rb +6 -4
- data/lib/sentry/utils/real_ip.rb +2 -0
- data/lib/sentry/utils/request_id.rb +2 -0
- data/lib/sentry/version.rb +3 -1
- data/lib/sentry-ruby.rb +212 -41
- data/sentry-ruby-core.gemspec +0 -1
- data/sentry-ruby.gemspec +0 -1
- metadata +7 -16
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
# @api private
|
5
|
+
class Envelope
|
6
|
+
class Item
|
7
|
+
attr_accessor :headers, :payload
|
8
|
+
|
9
|
+
def initialize(headers, payload)
|
10
|
+
@headers = headers
|
11
|
+
@payload = payload
|
12
|
+
end
|
13
|
+
|
14
|
+
def type
|
15
|
+
@headers[:type] || 'event'
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
<<~ITEM
|
20
|
+
#{JSON.generate(@headers)}
|
21
|
+
#{JSON.generate(@payload)}
|
22
|
+
ITEM
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_accessor :headers, :items
|
27
|
+
|
28
|
+
def initialize(headers = {})
|
29
|
+
@headers = headers
|
30
|
+
@items = []
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_item(headers, payload)
|
34
|
+
@items << Item.new(headers, payload)
|
35
|
+
end
|
36
|
+
|
37
|
+
def item_types
|
38
|
+
@items.map(&:type)
|
39
|
+
end
|
40
|
+
|
41
|
+
def event_id
|
42
|
+
@headers[:event_id]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/sentry/event.rb
CHANGED
@@ -10,31 +10,41 @@ require 'sentry/utils/custom_inspection'
|
|
10
10
|
|
11
11
|
module Sentry
|
12
12
|
class Event
|
13
|
+
# These are readable attributes.
|
13
14
|
SERIALIZEABLE_ATTRIBUTES = %i(
|
14
15
|
event_id level timestamp
|
15
16
|
release environment server_name modules
|
16
17
|
message user tags contexts extra
|
17
|
-
fingerprint breadcrumbs
|
18
|
+
fingerprint breadcrumbs transaction
|
18
19
|
platform sdk type
|
19
20
|
)
|
20
21
|
|
22
|
+
# These are writable attributes.
|
21
23
|
WRITER_ATTRIBUTES = SERIALIZEABLE_ATTRIBUTES - %i(type timestamp level)
|
22
24
|
|
23
25
|
MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
|
26
|
+
MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 200
|
24
27
|
|
25
|
-
SKIP_INSPECTION_ATTRIBUTES = [:@
|
28
|
+
SKIP_INSPECTION_ATTRIBUTES = [:@modules, :@stacktrace_builder, :@send_default_pii, :@trusted_proxies, :@rack_env_whitelist]
|
26
29
|
|
27
30
|
include CustomInspection
|
28
31
|
|
29
32
|
attr_writer(*WRITER_ATTRIBUTES)
|
30
33
|
attr_reader(*SERIALIZEABLE_ATTRIBUTES)
|
31
34
|
|
32
|
-
|
35
|
+
# @return [RequestInterface]
|
36
|
+
attr_reader :request
|
33
37
|
|
34
|
-
|
35
|
-
|
36
|
-
|
38
|
+
# @return [ExceptionInterface]
|
39
|
+
attr_reader :exception
|
40
|
+
|
41
|
+
# @return [ThreadsInterface]
|
42
|
+
attr_reader :threads
|
37
43
|
|
44
|
+
# @param configuration [Configuration]
|
45
|
+
# @param integration_meta [Hash, nil]
|
46
|
+
# @param message [String, nil]
|
47
|
+
def initialize(configuration:, integration_meta: nil, message: nil)
|
38
48
|
# Set some simple default values
|
39
49
|
@event_id = SecureRandom.uuid.delete("-")
|
40
50
|
@timestamp = Sentry.utc_now.iso8601
|
@@ -48,17 +58,25 @@ module Sentry
|
|
48
58
|
|
49
59
|
@fingerprint = []
|
50
60
|
|
61
|
+
# configuration data that's directly used by events
|
51
62
|
@server_name = configuration.server_name
|
52
63
|
@environment = configuration.environment
|
53
64
|
@release = configuration.release
|
54
65
|
@modules = configuration.gem_specs if configuration.send_modules
|
55
66
|
|
67
|
+
# configuration options to help events process data
|
68
|
+
@send_default_pii = configuration.send_default_pii
|
69
|
+
@trusted_proxies = configuration.trusted_proxies
|
70
|
+
@stacktrace_builder = configuration.stacktrace_builder
|
71
|
+
@rack_env_whitelist = configuration.rack_env_whitelist
|
72
|
+
|
56
73
|
@message = (message || "").byteslice(0..MAX_MESSAGE_SIZE_IN_BYTES)
|
57
74
|
|
58
75
|
self.level = :error
|
59
76
|
end
|
60
77
|
|
61
78
|
class << self
|
79
|
+
# @!visibility private
|
62
80
|
def get_log_message(event_hash)
|
63
81
|
message = event_hash[:message] || event_hash['message']
|
64
82
|
|
@@ -75,6 +93,7 @@ module Sentry
|
|
75
93
|
'<no message value>'
|
76
94
|
end
|
77
95
|
|
96
|
+
# @!visibility private
|
78
97
|
def get_message_from_exception(event_hash)
|
79
98
|
if exception = event_hash.dig(:exception, :values, 0)
|
80
99
|
"#{exception[:type]}: #{exception[:value]}"
|
@@ -84,21 +103,35 @@ module Sentry
|
|
84
103
|
end
|
85
104
|
end
|
86
105
|
|
106
|
+
# @deprecated This method will be removed in v5.0.0. Please just use Sentry.configuration
|
107
|
+
# @return [Configuration]
|
108
|
+
def configuration
|
109
|
+
Sentry.configuration
|
110
|
+
end
|
111
|
+
|
112
|
+
# Sets the event's timestamp.
|
113
|
+
# @param time [Time, Float]
|
114
|
+
# @return [void]
|
87
115
|
def timestamp=(time)
|
88
116
|
@timestamp = time.is_a?(Time) ? time.to_f : time
|
89
117
|
end
|
90
118
|
|
91
|
-
|
92
|
-
|
119
|
+
# Sets the event's level.
|
120
|
+
# @param level [String, Symbol]
|
121
|
+
# @return [void]
|
122
|
+
def level=(level) # needed to meet the Sentry spec
|
123
|
+
@level = level.to_s == "warn" ? :warning : level
|
93
124
|
end
|
94
125
|
|
126
|
+
# Sets the event's request environment data with RequestInterface.
|
127
|
+
# @see RequestInterface
|
128
|
+
# @param env [Hash]
|
129
|
+
# @return [void]
|
95
130
|
def rack_env=(env)
|
96
131
|
unless request || env.empty?
|
97
|
-
env = env.dup
|
98
|
-
|
99
132
|
add_request_interface(env)
|
100
133
|
|
101
|
-
if
|
134
|
+
if @send_default_pii
|
102
135
|
user[:ip_address] = calculate_real_ip_from_rack(env)
|
103
136
|
end
|
104
137
|
|
@@ -108,6 +141,7 @@ module Sentry
|
|
108
141
|
end
|
109
142
|
end
|
110
143
|
|
144
|
+
# @return [Hash]
|
111
145
|
def to_hash
|
112
146
|
data = serialize_attributes
|
113
147
|
data[:breadcrumbs] = breadcrumbs.to_hash if breadcrumbs
|
@@ -118,32 +152,35 @@ module Sentry
|
|
118
152
|
data
|
119
153
|
end
|
120
154
|
|
155
|
+
# @return [Hash]
|
121
156
|
def to_json_compatible
|
122
157
|
JSON.parse(JSON.generate(to_hash))
|
123
158
|
end
|
124
159
|
|
125
|
-
|
126
|
-
@request = Sentry::RequestInterface.build(env: env)
|
127
|
-
end
|
128
|
-
|
160
|
+
# @!visibility private
|
129
161
|
def add_threads_interface(backtrace: nil, **options)
|
130
162
|
@threads = ThreadsInterface.build(
|
131
163
|
backtrace: backtrace,
|
132
|
-
stacktrace_builder:
|
164
|
+
stacktrace_builder: @stacktrace_builder,
|
133
165
|
**options
|
134
166
|
)
|
135
167
|
end
|
136
168
|
|
169
|
+
# @!visibility private
|
137
170
|
def add_exception_interface(exception)
|
138
171
|
if exception.respond_to?(:sentry_context)
|
139
172
|
@extra.merge!(exception.sentry_context)
|
140
173
|
end
|
141
174
|
|
142
|
-
@exception = Sentry::ExceptionInterface.build(exception: exception, stacktrace_builder:
|
175
|
+
@exception = Sentry::ExceptionInterface.build(exception: exception, stacktrace_builder: @stacktrace_builder)
|
143
176
|
end
|
144
177
|
|
145
178
|
private
|
146
179
|
|
180
|
+
def add_request_interface(env)
|
181
|
+
@request = Sentry::RequestInterface.new(env: env, send_default_pii: @send_default_pii, rack_env_whitelist: @rack_env_whitelist)
|
182
|
+
end
|
183
|
+
|
147
184
|
def serialize_attributes
|
148
185
|
self.class::SERIALIZEABLE_ATTRIBUTES.each_with_object({}) do |att, memo|
|
149
186
|
if value = public_send(att)
|
@@ -160,7 +197,7 @@ module Sentry
|
|
160
197
|
:client_ip => env["HTTP_CLIENT_IP"],
|
161
198
|
:real_ip => env["HTTP_X_REAL_IP"],
|
162
199
|
:forwarded_for => env["HTTP_X_FORWARDED_FOR"],
|
163
|
-
:trusted_proxies =>
|
200
|
+
:trusted_proxies => @trusted_proxies
|
164
201
|
).calculate_ip
|
165
202
|
end
|
166
203
|
end
|
data/lib/sentry/exceptions.rb
CHANGED
data/lib/sentry/hub.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "sentry/scope"
|
2
4
|
require "sentry/client"
|
5
|
+
require "sentry/session"
|
3
6
|
|
4
7
|
module Sentry
|
5
8
|
class Hub
|
@@ -92,6 +95,8 @@ module Sentry
|
|
92
95
|
def capture_exception(exception, **options, &block)
|
93
96
|
check_argument_type!(exception, ::Exception)
|
94
97
|
|
98
|
+
return if Sentry.exception_captured?(exception)
|
99
|
+
|
95
100
|
return unless current_client
|
96
101
|
|
97
102
|
options[:hint] ||= {}
|
@@ -100,7 +105,12 @@ module Sentry
|
|
100
105
|
|
101
106
|
return unless event
|
102
107
|
|
103
|
-
|
108
|
+
current_scope.session&.update_from_exception(event.exception)
|
109
|
+
|
110
|
+
capture_event(event, **options, &block).tap do
|
111
|
+
# mark the exception as captured so we can use this information to avoid duplicated capturing
|
112
|
+
exception.instance_variable_set(Sentry::CAPTURED_SIGNATURE, true)
|
113
|
+
end
|
104
114
|
end
|
105
115
|
|
106
116
|
def capture_message(message, **options, &block)
|
@@ -112,6 +122,9 @@ module Sentry
|
|
112
122
|
options[:hint][:message] = message
|
113
123
|
backtrace = options.delete(:backtrace)
|
114
124
|
event = current_client.event_from_message(message, options[:hint], backtrace: backtrace)
|
125
|
+
|
126
|
+
return unless event
|
127
|
+
|
115
128
|
capture_event(event, **options, &block)
|
116
129
|
end
|
117
130
|
|
@@ -133,7 +146,6 @@ module Sentry
|
|
133
146
|
|
134
147
|
event = current_client.capture_event(event, scope, hint)
|
135
148
|
|
136
|
-
|
137
149
|
if event && configuration.debug
|
138
150
|
configuration.log_debug(event.to_json_compatible)
|
139
151
|
end
|
@@ -165,6 +177,30 @@ module Sentry
|
|
165
177
|
configuration.background_worker_threads = original_background_worker_threads
|
166
178
|
end
|
167
179
|
|
180
|
+
def start_session
|
181
|
+
return unless current_scope
|
182
|
+
current_scope.set_session(Session.new)
|
183
|
+
end
|
184
|
+
|
185
|
+
def end_session
|
186
|
+
return unless current_scope
|
187
|
+
session = current_scope.session
|
188
|
+
current_scope.set_session(nil)
|
189
|
+
|
190
|
+
return unless session
|
191
|
+
session.close
|
192
|
+
Sentry.session_flusher.add_session(session)
|
193
|
+
end
|
194
|
+
|
195
|
+
def with_session_tracking(&block)
|
196
|
+
return yield unless configuration.auto_session_tracking
|
197
|
+
|
198
|
+
start_session
|
199
|
+
yield
|
200
|
+
ensure
|
201
|
+
end_session
|
202
|
+
end
|
203
|
+
|
168
204
|
private
|
169
205
|
|
170
206
|
def current_layer
|
data/lib/sentry/integrable.rb
CHANGED
data/lib/sentry/interface.rb
CHANGED
@@ -1,15 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
class Interface
|
3
|
-
|
4
|
-
name = klass.name.split("::").last.downcase.gsub("interface", "")
|
5
|
-
registered[name.to_sym] = klass
|
6
|
-
super
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.registered
|
10
|
-
@@registered ||= {} # rubocop:disable Style/ClassVars
|
11
|
-
end
|
12
|
-
|
5
|
+
# @return [Hash]
|
13
6
|
def to_hash
|
14
7
|
Hash[instance_variables.map { |name| [name[1..-1].to_sym, instance_variable_get(name)] }]
|
15
8
|
end
|
@@ -1,15 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "set"
|
3
|
+
|
1
4
|
module Sentry
|
2
5
|
class ExceptionInterface < Interface
|
3
|
-
|
4
|
-
|
6
|
+
# @param exceptions [Array<SingleExceptionInterface>]
|
7
|
+
def initialize(exceptions:)
|
8
|
+
@values = exceptions
|
5
9
|
end
|
6
10
|
|
11
|
+
# @return [Hash]
|
7
12
|
def to_hash
|
8
13
|
data = super
|
9
14
|
data[:values] = data[:values].map(&:to_hash) if data[:values]
|
10
15
|
data
|
11
16
|
end
|
12
17
|
|
18
|
+
# Builds ExceptionInterface with given exception and stacktrace_builder.
|
19
|
+
# @param exception [Exception]
|
20
|
+
# @param stacktrace_builder [StacktraceBuilder]
|
21
|
+
# @see SingleExceptionInterface#build_with_stacktrace
|
22
|
+
# @see SingleExceptionInterface#initialize
|
23
|
+
# @return [ExceptionInterface]
|
13
24
|
def self.build(exception:, stacktrace_builder:)
|
14
25
|
exceptions = Sentry::Utils::ExceptionCauseChain.exception_to_array(exception).reverse
|
15
26
|
processed_backtrace_ids = Set.new
|
@@ -23,7 +34,7 @@ module Sentry
|
|
23
34
|
end
|
24
35
|
end
|
25
36
|
|
26
|
-
new(
|
37
|
+
new(exceptions: exceptions)
|
27
38
|
end
|
28
39
|
end
|
29
40
|
end
|
@@ -15,29 +15,45 @@ module Sentry
|
|
15
15
|
# https://github.com/getsentry/sentry/blob/master/src/sentry/conf/server.py
|
16
16
|
MAX_BODY_LIMIT = 4096 * 4
|
17
17
|
|
18
|
-
|
18
|
+
# @return [String]
|
19
|
+
attr_accessor :url
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
# @return [String]
|
22
|
+
attr_accessor :method
|
23
|
+
|
24
|
+
# @return [Hash]
|
25
|
+
attr_accessor :data
|
26
|
+
|
27
|
+
# @return [String]
|
28
|
+
attr_accessor :query_string
|
29
|
+
|
30
|
+
# @return [String]
|
31
|
+
attr_accessor :cookies
|
32
|
+
|
33
|
+
# @return [Hash]
|
34
|
+
attr_accessor :headers
|
25
35
|
|
26
|
-
|
27
|
-
|
36
|
+
# @return [Hash]
|
37
|
+
attr_accessor :env
|
38
|
+
|
39
|
+
# @param env [Hash]
|
40
|
+
# @param send_default_pii [Boolean]
|
41
|
+
# @param rack_env_whitelist [Array]
|
42
|
+
# @see Configuration#send_default_pii
|
43
|
+
# @see Configuration#rack_env_whitelist
|
44
|
+
def initialize(env:, send_default_pii:, rack_env_whitelist:)
|
45
|
+
env = env.dup
|
46
|
+
|
47
|
+
unless send_default_pii
|
28
48
|
# need to completely wipe out ip addresses
|
29
49
|
RequestInterface::IP_HEADERS.each do |header|
|
30
50
|
env.delete(header)
|
31
51
|
end
|
32
52
|
end
|
33
53
|
|
34
|
-
env
|
35
|
-
end
|
36
|
-
|
37
|
-
def initialize(request:)
|
38
|
-
env = request.env
|
54
|
+
request = ::Rack::Request.new(env)
|
39
55
|
|
40
|
-
if
|
56
|
+
if send_default_pii
|
41
57
|
self.data = read_data_from(request)
|
42
58
|
self.cookies = request.cookies
|
43
59
|
self.query_string = request.query_string
|
@@ -46,8 +62,8 @@ module Sentry
|
|
46
62
|
self.url = request.scheme && request.url.split('?').first
|
47
63
|
self.method = request.request_method
|
48
64
|
|
49
|
-
self.headers = filter_and_format_headers(env)
|
50
|
-
self.env = filter_and_format_env(env)
|
65
|
+
self.headers = filter_and_format_headers(env, send_default_pii)
|
66
|
+
self.env = filter_and_format_env(env, rack_env_whitelist)
|
51
67
|
end
|
52
68
|
|
53
69
|
private
|
@@ -65,13 +81,14 @@ module Sentry
|
|
65
81
|
e.message
|
66
82
|
end
|
67
83
|
|
68
|
-
def filter_and_format_headers(env)
|
84
|
+
def filter_and_format_headers(env, send_default_pii)
|
69
85
|
env.each_with_object({}) do |(key, value), memo|
|
70
86
|
begin
|
71
87
|
key = key.to_s # rack env can contain symbols
|
72
88
|
next memo['X-Request-Id'] ||= Utils::RequestId.read_from(env) if Utils::RequestId::REQUEST_ID_HEADERS.include?(key)
|
73
89
|
next if is_server_protocol?(key, value, env["SERVER_PROTOCOL"])
|
74
90
|
next if is_skippable_header?(key)
|
91
|
+
next if key == "HTTP_AUTHORIZATION" && !send_default_pii
|
75
92
|
|
76
93
|
# Rack stores headers as HTTP_WHAT_EVER, we need What-Ever
|
77
94
|
key = key.sub(/^HTTP_/, "")
|
@@ -116,11 +133,11 @@ module Sentry
|
|
116
133
|
key == 'HTTP_VERSION' && value == protocol_version
|
117
134
|
end
|
118
135
|
|
119
|
-
def filter_and_format_env(env)
|
120
|
-
return env if
|
136
|
+
def filter_and_format_env(env, rack_env_whitelist)
|
137
|
+
return env if rack_env_whitelist.empty?
|
121
138
|
|
122
139
|
env.select do |k, _v|
|
123
|
-
|
140
|
+
rack_env_whitelist.include? k.to_s
|
124
141
|
end
|
125
142
|
end
|
126
143
|
end
|
@@ -1,15 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
class StacktraceInterface
|
5
|
+
# @return [<Array[Frame]>]
|
3
6
|
attr_reader :frames
|
4
7
|
|
8
|
+
# @param frames [<Array[Frame]>]
|
5
9
|
def initialize(frames:)
|
6
10
|
@frames = frames
|
7
11
|
end
|
8
12
|
|
13
|
+
# @return [Hash]
|
9
14
|
def to_hash
|
10
15
|
{ frames: @frames.map(&:to_hash) }
|
11
16
|
end
|
12
17
|
|
18
|
+
# @return [String]
|
13
19
|
def inspect
|
14
20
|
@frames.map(&:to_s)
|
15
21
|
end
|
@@ -1,7 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
class StacktraceBuilder
|
3
|
-
|
5
|
+
# @return [String]
|
6
|
+
attr_reader :project_root
|
7
|
+
|
8
|
+
# @return [Regexp, nil]
|
9
|
+
attr_reader :app_dirs_pattern
|
10
|
+
|
11
|
+
# @return [LineCache]
|
12
|
+
attr_reader :linecache
|
13
|
+
|
14
|
+
# @return [Integer, nil]
|
15
|
+
attr_reader :context_lines
|
16
|
+
|
17
|
+
# @return [Proc, nil]
|
18
|
+
attr_reader :backtrace_cleanup_callback
|
4
19
|
|
20
|
+
# @param project_root [String]
|
21
|
+
# @param app_dirs_pattern [Regexp, nil]
|
22
|
+
# @param linecache [LineCache]
|
23
|
+
# @param context_lines [Integer, nil]
|
24
|
+
# @param backtrace_cleanup_callback [Proc, nil]
|
25
|
+
# @see Configuration#project_root
|
26
|
+
# @see Configuration#app_dirs_pattern
|
27
|
+
# @see Configuration#linecache
|
28
|
+
# @see Configuration#context_lines
|
29
|
+
# @see Configuration#backtrace_cleanup_callback
|
5
30
|
def initialize(project_root:, app_dirs_pattern:, linecache:, context_lines:, backtrace_cleanup_callback: nil)
|
6
31
|
@project_root = project_root
|
7
32
|
@app_dirs_pattern = app_dirs_pattern
|
@@ -10,17 +35,21 @@ module Sentry
|
|
10
35
|
@backtrace_cleanup_callback = backtrace_cleanup_callback
|
11
36
|
end
|
12
37
|
|
13
|
-
#
|
38
|
+
# Generates a StacktraceInterface with the given backtrace.
|
39
|
+
# You can pass a block to customize/exclude frames:
|
14
40
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
41
|
+
# @example
|
42
|
+
# builder.build(backtrace) do |frame|
|
43
|
+
# if frame.module.match?(/a_gem/)
|
44
|
+
# nil
|
45
|
+
# else
|
46
|
+
# frame
|
47
|
+
# end
|
21
48
|
# end
|
22
|
-
#
|
23
|
-
#
|
49
|
+
# @param backtrace [Array<String>]
|
50
|
+
# @param frame_callback [Proc]
|
51
|
+
# @yieldparam frame [StacktraceInterface::Frame]
|
52
|
+
# @return [StacktraceInterface]
|
24
53
|
def build(backtrace:, &frame_callback)
|
25
54
|
parsed_lines = parse_backtrace_lines(backtrace).select(&:file)
|
26
55
|
|
@@ -1,5 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
class ThreadsInterface
|
5
|
+
# @param crashed [Boolean]
|
6
|
+
# @param stacktrace [Array]
|
3
7
|
def initialize(crashed: false, stacktrace: nil)
|
4
8
|
@id = Thread.current.object_id
|
5
9
|
@name = Thread.current.name
|
@@ -8,6 +12,7 @@ module Sentry
|
|
8
12
|
@stacktrace = stacktrace
|
9
13
|
end
|
10
14
|
|
15
|
+
# @return [Hash]
|
11
16
|
def to_hash
|
12
17
|
{
|
13
18
|
values: [
|
@@ -22,8 +27,13 @@ module Sentry
|
|
22
27
|
}
|
23
28
|
end
|
24
29
|
|
25
|
-
#
|
26
|
-
#
|
30
|
+
# Builds the ThreadsInterface with given backtrace and stacktrace_builder.
|
31
|
+
# Patch this method if you want to change a threads interface's stacktrace frames.
|
32
|
+
# @see StacktraceBuilder.build
|
33
|
+
# @param backtrace [Array]
|
34
|
+
# @param stacktrace_builder [StacktraceBuilder]
|
35
|
+
# @param crashed [Hash]
|
36
|
+
# @return [ThreadsInterface]
|
27
37
|
def self.build(backtrace:, stacktrace_builder:, **options)
|
28
38
|
stacktrace = stacktrace_builder.build(backtrace: backtrace) if backtrace
|
29
39
|
new(**options, stacktrace: stacktrace)
|