sentry-ruby-core 5.0.1 → 5.1.1
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/Gemfile +1 -0
- data/lib/sentry/client.rb +1 -0
- data/lib/sentry/configuration.rb +1 -0
- data/lib/sentry/envelope.rb +33 -10
- data/lib/sentry/hub.rb +6 -1
- data/lib/sentry/interfaces/request.rb +3 -2
- data/lib/sentry/net/http.rb +3 -2
- data/lib/sentry/redis.rb +88 -0
- data/lib/sentry/scope.rb +1 -1
- data/lib/sentry/transaction.rb +4 -5
- data/lib/sentry/transport/http_transport.rb +3 -6
- data/lib/sentry/transport.rb +24 -16
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +58 -12
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bfc28e6f57d57de669447d555889196617f72ce09624b343cd284375021f60f5
|
4
|
+
data.tar.gz: 5a6af91521df30a18ac1d021b2e59cd9e871653f1325cf6d65346e6c1dc91d7e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fbe80e4c07f972d3babbf8c26c31cd97da84e91d77e86628a6931f35d7e66c83fb48461838d1a3e402361ee78dd9a3b6dfe849833f08a4573328d0eb4b5e66e1
|
7
|
+
data.tar.gz: 0f081f57f89207ece5279bd77fa89d311c3d516231421ccf60f4b9c232065a606d80eacc53ab460f12e087aa7b2fadfc4cdd4636863cb58261cc4e58a605ad2c
|
data/Gemfile
CHANGED
data/lib/sentry/client.rb
CHANGED
@@ -108,6 +108,7 @@ module Sentry
|
|
108
108
|
event.contexts.merge!(trace: transaction.get_trace_context)
|
109
109
|
event.timestamp = transaction.timestamp
|
110
110
|
event.start_timestamp = transaction.start_timestamp
|
111
|
+
event.tags = transaction.tags
|
111
112
|
|
112
113
|
finished_spans = transaction.span_recorder.spans.select { |span| span.timestamp && span != transaction }
|
113
114
|
event.spans = finished_spans.map(&:to_hash)
|
data/lib/sentry/configuration.rb
CHANGED
data/lib/sentry/envelope.rb
CHANGED
@@ -3,24 +3,47 @@
|
|
3
3
|
module Sentry
|
4
4
|
# @api private
|
5
5
|
class Envelope
|
6
|
-
|
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 = {})
|
7
29
|
@headers = headers
|
8
30
|
@items = []
|
9
31
|
end
|
10
32
|
|
11
33
|
def add_item(headers, payload)
|
12
|
-
@items <<
|
34
|
+
@items << Item.new(headers, payload)
|
13
35
|
end
|
14
36
|
|
15
37
|
def to_s
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
38
|
+
[JSON.generate(@headers), *@items.map(&:to_s)].join("\n")
|
39
|
+
end
|
40
|
+
|
41
|
+
def item_types
|
42
|
+
@items.map(&:type)
|
43
|
+
end
|
44
|
+
|
45
|
+
def event_id
|
46
|
+
@headers[:event_id]
|
24
47
|
end
|
25
48
|
end
|
26
49
|
end
|
data/lib/sentry/hub.rb
CHANGED
@@ -94,6 +94,8 @@ module Sentry
|
|
94
94
|
def capture_exception(exception, **options, &block)
|
95
95
|
check_argument_type!(exception, ::Exception)
|
96
96
|
|
97
|
+
return if Sentry.exception_captured?(exception)
|
98
|
+
|
97
99
|
return unless current_client
|
98
100
|
|
99
101
|
options[:hint] ||= {}
|
@@ -102,7 +104,10 @@ module Sentry
|
|
102
104
|
|
103
105
|
return unless event
|
104
106
|
|
105
|
-
capture_event(event, **options, &block)
|
107
|
+
capture_event(event, **options, &block).tap do
|
108
|
+
# mark the exception as captured so we can use this information to avoid duplicated capturing
|
109
|
+
exception.instance_variable_set(Sentry::CAPTURED_SIGNATURE, true)
|
110
|
+
end
|
106
111
|
end
|
107
112
|
|
108
113
|
def capture_message(message, **options, &block)
|
@@ -62,7 +62,7 @@ module Sentry
|
|
62
62
|
self.url = request.scheme && request.url.split('?').first
|
63
63
|
self.method = request.request_method
|
64
64
|
|
65
|
-
self.headers = filter_and_format_headers(env)
|
65
|
+
self.headers = filter_and_format_headers(env, send_default_pii)
|
66
66
|
self.env = filter_and_format_env(env, rack_env_whitelist)
|
67
67
|
end
|
68
68
|
|
@@ -81,13 +81,14 @@ module Sentry
|
|
81
81
|
e.message
|
82
82
|
end
|
83
83
|
|
84
|
-
def filter_and_format_headers(env)
|
84
|
+
def filter_and_format_headers(env, send_default_pii)
|
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
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
|
+
next if key == "HTTP_AUTHORIZATION" && !send_default_pii
|
91
92
|
|
92
93
|
# Rack stores headers as HTTP_WHAT_EVER, we need What-Ever
|
93
94
|
key = key.sub(/^HTTP_/, "")
|
data/lib/sentry/net/http.rb
CHANGED
@@ -6,7 +6,8 @@ module Sentry
|
|
6
6
|
# @api private
|
7
7
|
module Net
|
8
8
|
module HTTP
|
9
|
-
OP_NAME = "
|
9
|
+
OP_NAME = "http.client"
|
10
|
+
BREADCRUMB_CATEGORY = "net.http"
|
10
11
|
|
11
12
|
# To explain how the entire thing works, we need to know how the original Net::HTTP#request works
|
12
13
|
# Here's part of its definition. As you can see, it usually calls itself inside a #start block
|
@@ -53,7 +54,7 @@ module Sentry
|
|
53
54
|
|
54
55
|
crumb = Sentry::Breadcrumb.new(
|
55
56
|
level: :info,
|
56
|
-
category:
|
57
|
+
category: BREADCRUMB_CATEGORY,
|
57
58
|
type: :info,
|
58
59
|
data: {
|
59
60
|
status: res.code.to_i,
|
data/lib/sentry/redis.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
# @api private
|
5
|
+
class Redis
|
6
|
+
OP_NAME ||= "db.redis.command"
|
7
|
+
LOGGER_NAME ||= :redis_logger
|
8
|
+
|
9
|
+
def initialize(commands, host, port, db)
|
10
|
+
@commands, @host, @port, @db = commands, host, port, db
|
11
|
+
end
|
12
|
+
|
13
|
+
def instrument
|
14
|
+
return yield unless Sentry.initialized?
|
15
|
+
|
16
|
+
record_span do
|
17
|
+
yield.tap do
|
18
|
+
record_breadcrumb
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :commands, :host, :port, :db
|
26
|
+
|
27
|
+
def record_span
|
28
|
+
return yield unless (transaction = Sentry.get_current_scope.get_transaction) && transaction.sampled
|
29
|
+
|
30
|
+
sentry_span = transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
|
31
|
+
|
32
|
+
yield.tap do
|
33
|
+
sentry_span.set_description(commands_description)
|
34
|
+
sentry_span.set_data(:server, server_description)
|
35
|
+
sentry_span.set_timestamp(Sentry.utc_now.to_f)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def record_breadcrumb
|
40
|
+
return unless Sentry.configuration.breadcrumbs_logger.include?(LOGGER_NAME)
|
41
|
+
|
42
|
+
Sentry.add_breadcrumb(
|
43
|
+
Sentry::Breadcrumb.new(
|
44
|
+
level: :info,
|
45
|
+
category: OP_NAME,
|
46
|
+
type: :info,
|
47
|
+
data: {
|
48
|
+
commands: parsed_commands,
|
49
|
+
server: server_description
|
50
|
+
}
|
51
|
+
)
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
def commands_description
|
56
|
+
parsed_commands.map do |statement|
|
57
|
+
statement.values.join(" ").strip
|
58
|
+
end.join(", ")
|
59
|
+
end
|
60
|
+
|
61
|
+
def parsed_commands
|
62
|
+
commands.map do |statement|
|
63
|
+
command, key, *_values = statement
|
64
|
+
|
65
|
+
{ command: command.to_s.upcase, key: key }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def server_description
|
70
|
+
"#{host}:#{port}/#{db}"
|
71
|
+
end
|
72
|
+
|
73
|
+
module Client
|
74
|
+
def logging(commands, &block)
|
75
|
+
Sentry::Redis.new(commands, host, port, db).instrument do
|
76
|
+
super
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
if defined?(::Redis::Client)
|
84
|
+
Sentry.register_patch do
|
85
|
+
patch = Sentry::Redis::Client
|
86
|
+
Redis::Client.prepend(patch) unless Redis::Client.ancestors.include?(patch)
|
87
|
+
end
|
88
|
+
end
|
data/lib/sentry/scope.rb
CHANGED
data/lib/sentry/transaction.rb
CHANGED
@@ -164,13 +164,12 @@ module Sentry
|
|
164
164
|
@name = UNLABELD_NAME
|
165
165
|
end
|
166
166
|
|
167
|
-
|
167
|
+
if @sampled
|
168
|
+
event = hub.current_client.event_from_transaction(self)
|
169
|
+
hub.capture_event(event)
|
170
|
+
else
|
168
171
|
hub.current_client.transport.record_lost_event(:sample_rate, 'transaction')
|
169
|
-
return
|
170
172
|
end
|
171
|
-
|
172
|
-
event = hub.current_client.event_from_transaction(self)
|
173
|
-
hub.capture_event(event)
|
174
173
|
end
|
175
174
|
|
176
175
|
protected
|
@@ -129,17 +129,14 @@ module Sentry
|
|
129
129
|
def conn
|
130
130
|
server = URI(@dsn.server)
|
131
131
|
|
132
|
-
use_ssl = server.scheme == "https"
|
133
|
-
port = use_ssl ? 443 : 80
|
134
|
-
|
135
132
|
connection =
|
136
133
|
if proxy = @transport_configuration.proxy
|
137
|
-
::Net::HTTP.new(server.hostname, port, proxy[:uri].hostname, proxy[:uri].port, proxy[:user], proxy[:password])
|
134
|
+
::Net::HTTP.new(server.hostname, server.port, proxy[:uri].hostname, proxy[:uri].port, proxy[:user], proxy[:password])
|
138
135
|
else
|
139
|
-
::Net::HTTP.new(server.hostname, port, nil)
|
136
|
+
::Net::HTTP.new(server.hostname, server.port, nil)
|
140
137
|
end
|
141
138
|
|
142
|
-
connection.use_ssl =
|
139
|
+
connection.use_ssl = server.scheme == "https"
|
143
140
|
connection.read_timeout = @transport_configuration.timeout
|
144
141
|
connection.write_timeout = @transport_configuration.timeout if connection.respond_to?(:write_timeout)
|
145
142
|
connection.open_timeout = @transport_configuration.open_timeout
|
data/lib/sentry/transport.rb
CHANGED
@@ -46,23 +46,19 @@ module Sentry
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def send_event(event)
|
49
|
-
|
50
|
-
|
49
|
+
envelope = envelope_from_event(event)
|
50
|
+
send_envelope(envelope)
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
record_lost_event(:ratelimit_backoff, item_type)
|
55
|
-
|
56
|
-
return
|
57
|
-
end
|
58
|
-
|
59
|
-
encoded_data = encode(event)
|
52
|
+
event
|
53
|
+
end
|
60
54
|
|
61
|
-
|
55
|
+
def send_envelope(envelope)
|
56
|
+
reject_rate_limited_items(envelope)
|
62
57
|
|
63
|
-
|
58
|
+
return if envelope.items.empty?
|
64
59
|
|
65
|
-
|
60
|
+
log_info("[Transport] Sending envelope with items [#{envelope.item_types.join(', ')}] #{envelope.event_id} to Sentry")
|
61
|
+
send_data(envelope.to_s)
|
66
62
|
end
|
67
63
|
|
68
64
|
def is_rate_limited?(item_type)
|
@@ -106,7 +102,7 @@ module Sentry
|
|
106
102
|
'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
|
107
103
|
end
|
108
104
|
|
109
|
-
def
|
105
|
+
def envelope_from_event(event)
|
110
106
|
# Convert to hash
|
111
107
|
event_payload = event.to_hash
|
112
108
|
event_id = event_payload[:event_id] || event_payload["event_id"]
|
@@ -129,9 +125,8 @@ module Sentry
|
|
129
125
|
client_report_headers, client_report_payload = fetch_pending_client_report
|
130
126
|
envelope.add_item(client_report_headers, client_report_payload) if client_report_headers
|
131
127
|
|
132
|
-
log_info("Sending envelope [#{item_type}] #{event_id} to Sentry")
|
133
128
|
|
134
|
-
envelope
|
129
|
+
envelope
|
135
130
|
end
|
136
131
|
|
137
132
|
def record_lost_event(reason, item_type)
|
@@ -173,6 +168,19 @@ module Sentry
|
|
173
168
|
|
174
169
|
[item_header, item_payload]
|
175
170
|
end
|
171
|
+
|
172
|
+
def reject_rate_limited_items(envelope)
|
173
|
+
envelope.items.reject! do |item|
|
174
|
+
if is_rate_limited?(item.type)
|
175
|
+
log_info("[Transport] Envelope item [#{item.type}] not sent: rate limiting")
|
176
|
+
record_lost_event(:ratelimit_backoff, item.type)
|
177
|
+
|
178
|
+
true
|
179
|
+
else
|
180
|
+
false
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
176
184
|
end
|
177
185
|
end
|
178
186
|
|
data/lib/sentry/version.rb
CHANGED
data/lib/sentry-ruby.rb
CHANGED
@@ -31,6 +31,8 @@ end
|
|
31
31
|
module Sentry
|
32
32
|
META = { "name" => "sentry.ruby", "version" => Sentry::VERSION }.freeze
|
33
33
|
|
34
|
+
CAPTURED_SIGNATURE = :@__sentry_captured
|
35
|
+
|
34
36
|
LOGGER_PROGNAME = "sentry".freeze
|
35
37
|
|
36
38
|
SENTRY_TRACE_HEADER_NAME = "sentry-trace".freeze
|
@@ -111,9 +113,17 @@ module Sentry
|
|
111
113
|
|
112
114
|
# @!method configuration
|
113
115
|
# @!macro configuration
|
116
|
+
def configuration
|
117
|
+
return unless initialized?
|
118
|
+
get_current_client.configuration
|
119
|
+
end
|
120
|
+
|
114
121
|
# @!method send_event
|
115
122
|
# @!macro send_event
|
116
|
-
|
123
|
+
def send_event(*args)
|
124
|
+
return unless initialized?
|
125
|
+
get_current_client.send_event(*args)
|
126
|
+
end
|
117
127
|
|
118
128
|
# @!macro [new] set_extras
|
119
129
|
# Updates the scope's extras attribute by merging with the old value.
|
@@ -135,13 +145,31 @@ module Sentry
|
|
135
145
|
|
136
146
|
# @!method set_tags
|
137
147
|
# @!macro set_tags
|
148
|
+
def set_tags(*args)
|
149
|
+
return unless initialized?
|
150
|
+
get_current_scope.set_tags(*args)
|
151
|
+
end
|
152
|
+
|
138
153
|
# @!method set_extras
|
139
154
|
# @!macro set_extras
|
155
|
+
def set_extras(*args)
|
156
|
+
return unless initialized?
|
157
|
+
get_current_scope.set_extras(*args)
|
158
|
+
end
|
159
|
+
|
140
160
|
# @!method set_user
|
141
161
|
# @!macro set_user
|
162
|
+
def set_user(*args)
|
163
|
+
return unless initialized?
|
164
|
+
get_current_scope.set_user(*args)
|
165
|
+
end
|
166
|
+
|
142
167
|
# @!method set_context
|
143
168
|
# @!macro set_context
|
144
|
-
|
169
|
+
def set_context(*args)
|
170
|
+
return unless initialized?
|
171
|
+
get_current_scope.set_context(*args)
|
172
|
+
end
|
145
173
|
|
146
174
|
##### Main APIs #####
|
147
175
|
|
@@ -201,7 +229,8 @@ module Sentry
|
|
201
229
|
#
|
202
230
|
# @return [Breadcrumb, nil]
|
203
231
|
def add_breadcrumb(breadcrumb, **options)
|
204
|
-
|
232
|
+
return unless initialized?
|
233
|
+
get_current_hub.add_breadcrumb(breadcrumb, **options)
|
205
234
|
end
|
206
235
|
|
207
236
|
# Returns the current active hub.
|
@@ -221,14 +250,16 @@ module Sentry
|
|
221
250
|
# Returns the current active client.
|
222
251
|
# @return [Client, nil]
|
223
252
|
def get_current_client
|
224
|
-
|
253
|
+
return unless initialized?
|
254
|
+
get_current_hub.current_client
|
225
255
|
end
|
226
256
|
|
227
257
|
# Returns the current active scope.
|
228
258
|
#
|
229
259
|
# @return [Scope, nil]
|
230
260
|
def get_current_scope
|
231
|
-
|
261
|
+
return unless initialized?
|
262
|
+
get_current_hub.current_scope
|
232
263
|
end
|
233
264
|
|
234
265
|
# Clones the main thread's active hub and stores it to the current thread.
|
@@ -250,7 +281,8 @@ module Sentry
|
|
250
281
|
# @yieldparam scope [Scope]
|
251
282
|
# @return [void]
|
252
283
|
def configure_scope(&block)
|
253
|
-
|
284
|
+
return unless initialized?
|
285
|
+
get_current_hub.configure_scope(&block)
|
254
286
|
end
|
255
287
|
|
256
288
|
# Takes a block and yields a temporary scope.
|
@@ -274,7 +306,8 @@ module Sentry
|
|
274
306
|
# @yieldparam scope [Scope]
|
275
307
|
# @return [void]
|
276
308
|
def with_scope(&block)
|
277
|
-
|
309
|
+
return unless initialized?
|
310
|
+
get_current_hub.with_scope(&block)
|
278
311
|
end
|
279
312
|
|
280
313
|
# Takes an exception and reports it to Sentry via the currently active hub.
|
@@ -282,7 +315,8 @@ module Sentry
|
|
282
315
|
# @yieldparam scope [Scope]
|
283
316
|
# @return [Event, nil]
|
284
317
|
def capture_exception(exception, **options, &block)
|
285
|
-
|
318
|
+
return unless initialized?
|
319
|
+
get_current_hub.capture_exception(exception, **options, &block)
|
286
320
|
end
|
287
321
|
|
288
322
|
# Takes a message string and reports it to Sentry via the currently active hub.
|
@@ -290,30 +324,41 @@ module Sentry
|
|
290
324
|
# @yieldparam scope [Scope]
|
291
325
|
# @return [Event, nil]
|
292
326
|
def capture_message(message, **options, &block)
|
293
|
-
|
327
|
+
return unless initialized?
|
328
|
+
get_current_hub.capture_message(message, **options, &block)
|
294
329
|
end
|
295
330
|
|
296
331
|
# Takes an instance of Sentry::Event and dispatches it to the currently active hub.
|
297
332
|
#
|
298
333
|
# @return [Event, nil]
|
299
334
|
def capture_event(event)
|
300
|
-
|
335
|
+
return unless initialized?
|
336
|
+
get_current_hub.capture_event(event)
|
301
337
|
end
|
302
338
|
|
303
339
|
# Takes or initializes a new Sentry::Transaction and makes a sampling decision for it.
|
304
340
|
#
|
305
341
|
# @return [Transaction, nil]
|
306
342
|
def start_transaction(**options)
|
307
|
-
|
343
|
+
return unless initialized?
|
344
|
+
get_current_hub.start_transaction(**options)
|
308
345
|
end
|
309
346
|
|
310
347
|
# Returns the id of the lastly reported Sentry::Event.
|
311
348
|
#
|
312
349
|
# @return [String, nil]
|
313
350
|
def last_event_id
|
314
|
-
|
351
|
+
return unless initialized?
|
352
|
+
get_current_hub.last_event_id
|
315
353
|
end
|
316
354
|
|
355
|
+
# Checks if the exception object has been captured by the SDK.
|
356
|
+
#
|
357
|
+
# @return [Boolean]
|
358
|
+
def exception_captured?(exc)
|
359
|
+
return false unless initialized?
|
360
|
+
!!exc.instance_variable_get(CAPTURED_SIGNATURE)
|
361
|
+
end
|
317
362
|
|
318
363
|
##### Helpers #####
|
319
364
|
|
@@ -344,3 +389,4 @@ end
|
|
344
389
|
|
345
390
|
# patches
|
346
391
|
require "sentry/net/http"
|
392
|
+
require "sentry/redis"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sentry-ruby-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sentry Team
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -73,6 +73,7 @@ files:
|
|
73
73
|
- lib/sentry/rack.rb
|
74
74
|
- lib/sentry/rack/capture_exceptions.rb
|
75
75
|
- lib/sentry/rake.rb
|
76
|
+
- lib/sentry/redis.rb
|
76
77
|
- lib/sentry/release_detector.rb
|
77
78
|
- lib/sentry/scope.rb
|
78
79
|
- lib/sentry/span.rb
|