sentry-ruby-core 5.3.1 → 5.4.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/Gemfile +0 -1
- data/lib/sentry/client.rb +8 -1
- data/lib/sentry/envelope.rb +51 -0
- data/lib/sentry/event.rb +0 -1
- data/lib/sentry/interfaces/exception.rb +3 -0
- data/lib/sentry/rack/capture_exceptions.rb +8 -4
- data/lib/sentry/session_flusher.rb +11 -1
- data/lib/sentry/test_helper.rb +76 -0
- data/lib/sentry/transport.rb +3 -17
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +44 -4
- data/sentry-ruby-core.gemspec +1 -4
- data/sentry-ruby.gemspec +2 -1
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '05368ec66748ebeba74ec529e6395ce1ad5eb36f1beff0f7014e041a507099fe'
|
4
|
+
data.tar.gz: 150e09181157a7f36a21a46aeffdc37f47db942d967dbf206167ddb6208e6b51
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eec3eb3c33f43854ff89fdf19c5b0b53726c9f79e8e9325969d5241f51490c1096234cbc27aa090bf408207142a265ec9c4eebdf06d159771a5e22a44d405d8b
|
7
|
+
data.tar.gz: e2e50b8e694d3eea9606a41dfcca942ebc41a5e64f128bc455ad34ee9ad5806ae1794993306706039270439bfa26cf7f46614ccf6525d8ecc0a46db6dad3d60a
|
data/Gemfile
CHANGED
data/lib/sentry/client.rb
CHANGED
@@ -167,7 +167,14 @@ module Sentry
|
|
167
167
|
def dispatch_async_event(async_block, event, hint)
|
168
168
|
# We have to convert to a JSON-like hash, because background job
|
169
169
|
# processors (esp ActiveJob) may not like weird types in the event hash
|
170
|
-
|
170
|
+
|
171
|
+
event_hash =
|
172
|
+
begin
|
173
|
+
event.to_json_compatible
|
174
|
+
rescue => e
|
175
|
+
log_error("Converting #{event.type} (#{event.event_id}) to JSON compatible hash failed", e, debug: configuration.debug)
|
176
|
+
return
|
177
|
+
end
|
171
178
|
|
172
179
|
if async_block.arity == 2
|
173
180
|
hint = JSON.parse(JSON.generate(hint))
|
data/lib/sentry/envelope.rb
CHANGED
@@ -4,6 +4,9 @@ module Sentry
|
|
4
4
|
# @api private
|
5
5
|
class Envelope
|
6
6
|
class Item
|
7
|
+
STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD = 500
|
8
|
+
MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 200
|
9
|
+
|
7
10
|
attr_accessor :headers, :payload
|
8
11
|
|
9
12
|
def initialize(headers, payload)
|
@@ -21,6 +24,54 @@ module Sentry
|
|
21
24
|
#{JSON.generate(@payload)}
|
22
25
|
ITEM
|
23
26
|
end
|
27
|
+
|
28
|
+
def serialize
|
29
|
+
result = to_s
|
30
|
+
|
31
|
+
if result.bytesize > MAX_SERIALIZED_PAYLOAD_SIZE
|
32
|
+
remove_breadcrumbs!
|
33
|
+
result = to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
if result.bytesize > MAX_SERIALIZED_PAYLOAD_SIZE
|
37
|
+
reduce_stacktrace!
|
38
|
+
result = to_s
|
39
|
+
end
|
40
|
+
|
41
|
+
[result, result.bytesize > MAX_SERIALIZED_PAYLOAD_SIZE]
|
42
|
+
end
|
43
|
+
|
44
|
+
def size_breakdown
|
45
|
+
payload.map do |key, value|
|
46
|
+
"#{key}: #{JSON.generate(value).bytesize}"
|
47
|
+
end.join(", ")
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def remove_breadcrumbs!
|
53
|
+
if payload.key?(:breadcrumbs)
|
54
|
+
payload.delete(:breadcrumbs)
|
55
|
+
elsif payload.key?("breadcrumbs")
|
56
|
+
payload.delete("breadcrumbs")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def reduce_stacktrace!
|
61
|
+
if exceptions = payload.dig(:exception, :values) || payload.dig("exception", "values")
|
62
|
+
exceptions.each do |exception|
|
63
|
+
# in most cases there is only one exception (2 or 3 when have multiple causes), so we won't loop through this double condition much
|
64
|
+
traces = exception.dig(:stacktrace, :frames) || exception.dig("stacktrace", "frames")
|
65
|
+
|
66
|
+
if traces && traces.size > STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD
|
67
|
+
size_on_both_ends = STACKTRACE_FRAME_LIMIT_ON_OVERSIZED_PAYLOAD / 2
|
68
|
+
traces.replace(
|
69
|
+
traces[0..(size_on_both_ends - 1)] + traces[-size_on_both_ends..-1],
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
24
75
|
end
|
25
76
|
|
26
77
|
attr_accessor :headers, :items
|
data/lib/sentry/event.rb
CHANGED
@@ -26,7 +26,6 @@ module Sentry
|
|
26
26
|
WRITER_ATTRIBUTES = SERIALIZEABLE_ATTRIBUTES - %i(type timestamp level)
|
27
27
|
|
28
28
|
MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
|
29
|
-
MAX_SERIALIZED_PAYLOAD_SIZE = 1024 * 200
|
30
29
|
|
31
30
|
SKIP_INSPECTION_ATTRIBUTES = [:@modules, :@stacktrace_builder, :@send_default_pii, :@trusted_proxies, :@rack_env_whitelist]
|
32
31
|
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module Sentry
|
4
4
|
module Rack
|
5
5
|
class CaptureExceptions
|
6
|
+
ERROR_EVENT_ID_KEY = "sentry.error_event_id"
|
7
|
+
|
6
8
|
def initialize(app)
|
7
9
|
@app = app
|
8
10
|
end
|
@@ -28,13 +30,13 @@ module Sentry
|
|
28
30
|
finish_transaction(transaction, 500)
|
29
31
|
raise # Don't capture Sentry errors
|
30
32
|
rescue Exception => e
|
31
|
-
capture_exception(e)
|
33
|
+
capture_exception(e, env)
|
32
34
|
finish_transaction(transaction, 500)
|
33
35
|
raise
|
34
36
|
end
|
35
37
|
|
36
38
|
exception = collect_exception(env)
|
37
|
-
capture_exception(exception) if exception
|
39
|
+
capture_exception(exception, env) if exception
|
38
40
|
|
39
41
|
finish_transaction(transaction, response[0])
|
40
42
|
|
@@ -53,8 +55,10 @@ module Sentry
|
|
53
55
|
"rack.request".freeze
|
54
56
|
end
|
55
57
|
|
56
|
-
def capture_exception(exception)
|
57
|
-
Sentry.capture_exception(exception)
|
58
|
+
def capture_exception(exception, env)
|
59
|
+
Sentry.capture_exception(exception).tap do |event|
|
60
|
+
env[ERROR_EVENT_ID_KEY] = event.event_id if event
|
61
|
+
end
|
58
62
|
end
|
59
63
|
|
60
64
|
def start_transaction(env, scope)
|
@@ -8,6 +8,7 @@ module Sentry
|
|
8
8
|
|
9
9
|
def initialize(configuration, client)
|
10
10
|
@thread = nil
|
11
|
+
@exited = false
|
11
12
|
@client = client
|
12
13
|
@pending_aggregates = {}
|
13
14
|
@release = configuration.release
|
@@ -29,9 +30,16 @@ module Sentry
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def add_session(session)
|
33
|
+
return if @exited
|
32
34
|
return unless @release
|
33
35
|
|
34
|
-
|
36
|
+
begin
|
37
|
+
ensure_thread
|
38
|
+
rescue ThreadError
|
39
|
+
log_debug("Session flusher thread creation failed")
|
40
|
+
@exited = true
|
41
|
+
return
|
42
|
+
end
|
35
43
|
|
36
44
|
return unless Session::AGGREGATE_STATUSES.include?(session.status)
|
37
45
|
@pending_aggregates[session.aggregation_key] ||= init_aggregates(session.aggregation_key)
|
@@ -40,6 +48,8 @@ module Sentry
|
|
40
48
|
|
41
49
|
def kill
|
42
50
|
log_debug("Killing session flusher")
|
51
|
+
|
52
|
+
@exited = true
|
43
53
|
@thread&.kill
|
44
54
|
end
|
45
55
|
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Sentry
|
2
|
+
module TestHelper
|
3
|
+
DUMMY_DSN = 'http://12345:67890@sentry.localdomain/sentry/42'
|
4
|
+
|
5
|
+
# Alters the existing SDK configuration with test-suitable options. Mainly:
|
6
|
+
# - Sets a dummy DSN instead of `nil` or an actual DSN.
|
7
|
+
# - Sets the transport to DummyTransport, which allows easy access to the captured events.
|
8
|
+
# - Disables background worker.
|
9
|
+
# - Makes sure the SDK is enabled under the current environment ("test" in most cases).
|
10
|
+
#
|
11
|
+
# It should be called **before** every test case.
|
12
|
+
#
|
13
|
+
# @yieldparam config [Configuration]
|
14
|
+
# @return [void]
|
15
|
+
def setup_sentry_test(&block)
|
16
|
+
raise "please make sure the SDK is initialized for testing" unless Sentry.initialized?
|
17
|
+
copied_config = Sentry.configuration.dup
|
18
|
+
# configure dummy DSN, so the events will not be sent to the actual service
|
19
|
+
copied_config.dsn = DUMMY_DSN
|
20
|
+
# set transport to DummyTransport, so we can easily intercept the captured events
|
21
|
+
copied_config.transport.transport_class = Sentry::DummyTransport
|
22
|
+
# make sure SDK allows sending under the current environment
|
23
|
+
copied_config.enabled_environments << copied_config.environment unless copied_config.enabled_environments.include?(copied_config.environment)
|
24
|
+
# disble async event sending
|
25
|
+
copied_config.background_worker_threads = 0
|
26
|
+
|
27
|
+
# user can overwrite some of the configs, with a few exceptions like:
|
28
|
+
# - capture_exception_frame_locals
|
29
|
+
# - auto_session_tracking
|
30
|
+
block&.call(copied_config)
|
31
|
+
|
32
|
+
test_client = Sentry::Client.new(copied_config)
|
33
|
+
Sentry.get_current_hub.bind_client(test_client)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Clears all stored events and envelopes.
|
37
|
+
# It should be called **after** every test case.
|
38
|
+
# @return [void]
|
39
|
+
def teardown_sentry_test
|
40
|
+
return unless Sentry.initialized?
|
41
|
+
|
42
|
+
sentry_transport.events = []
|
43
|
+
sentry_transport.envelopes = []
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [Transport]
|
47
|
+
def sentry_transport
|
48
|
+
Sentry.get_current_client.transport
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns the captured event objects.
|
52
|
+
# @return [Array<Event>]
|
53
|
+
def sentry_events
|
54
|
+
sentry_transport.events
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns the captured envelope objects.
|
58
|
+
# @return [Array<Envelope>]
|
59
|
+
def sentry_envelopes
|
60
|
+
sentry_transport.envelopes
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the last captured event object.
|
64
|
+
# @return [Event, nil]
|
65
|
+
def last_sentry_event
|
66
|
+
sentry_events.last
|
67
|
+
end
|
68
|
+
|
69
|
+
# Extracts SDK's internal exception container (not actual exception objects) from an given event.
|
70
|
+
# @return [Array<Sentry::SingleExceptionInterface>]
|
71
|
+
def extract_sentry_exceptions(event)
|
72
|
+
event&.exception&.values || []
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
data/lib/sentry/transport.rb
CHANGED
@@ -70,24 +70,10 @@ module Sentry
|
|
70
70
|
serialized_results = []
|
71
71
|
|
72
72
|
envelope.items.each do |item|
|
73
|
-
result = item.
|
73
|
+
result, oversized = item.serialize
|
74
74
|
|
75
|
-
if
|
76
|
-
|
77
|
-
item.payload.delete(:breadcrumbs)
|
78
|
-
elsif item.payload.key?("breadcrumbs")
|
79
|
-
item.payload.delete("breadcrumbs")
|
80
|
-
end
|
81
|
-
|
82
|
-
result = item.to_s
|
83
|
-
end
|
84
|
-
|
85
|
-
if result.bytesize > Event::MAX_SERIALIZED_PAYLOAD_SIZE
|
86
|
-
size_breakdown = item.payload.map do |key, value|
|
87
|
-
"#{key}: #{JSON.generate(value).bytesize}"
|
88
|
-
end.join(", ")
|
89
|
-
|
90
|
-
log_debug("Envelope item [#{item.type}] is still oversized without breadcrumbs: {#{size_breakdown}}")
|
75
|
+
if oversized
|
76
|
+
log_info("Envelope item [#{item.type}] is still oversized after size reduction: {#{item.size_breakdown}}")
|
91
77
|
|
92
78
|
next
|
93
79
|
end
|
data/lib/sentry/version.rb
CHANGED
data/lib/sentry-ruby.rb
CHANGED
@@ -60,11 +60,11 @@ module Sentry
|
|
60
60
|
end
|
61
61
|
|
62
62
|
# @!attribute [rw] background_worker
|
63
|
-
# @return [BackgroundWorker]
|
63
|
+
# @return [BackgroundWorker, nil]
|
64
64
|
attr_accessor :background_worker
|
65
65
|
|
66
66
|
# @!attribute [r] session_flusher
|
67
|
-
# @return [SessionFlusher]
|
67
|
+
# @return [SessionFlusher, nil]
|
68
68
|
attr_reader :session_flusher
|
69
69
|
|
70
70
|
##### Patch Registration #####
|
@@ -213,10 +213,30 @@ module Sentry
|
|
213
213
|
exception_locals_tp.enable
|
214
214
|
end
|
215
215
|
|
216
|
-
at_exit
|
217
|
-
|
216
|
+
at_exit { close }
|
217
|
+
end
|
218
|
+
|
219
|
+
# Flushes pending events and cleans up SDK state.
|
220
|
+
# SDK will stop sending events and all top-level APIs will be no-ops after this.
|
221
|
+
#
|
222
|
+
# @return [void]
|
223
|
+
def close
|
224
|
+
if @background_worker
|
218
225
|
@background_worker.shutdown
|
226
|
+
@background_worker = nil
|
219
227
|
end
|
228
|
+
|
229
|
+
if @session_flusher
|
230
|
+
@session_flusher.kill
|
231
|
+
@session_flusher = nil
|
232
|
+
end
|
233
|
+
|
234
|
+
if configuration&.capture_exception_frame_locals
|
235
|
+
exception_locals_tp.disable
|
236
|
+
end
|
237
|
+
|
238
|
+
@main_hub = nil
|
239
|
+
Thread.current.thread_variable_set(THREAD_LOCAL, nil)
|
220
240
|
end
|
221
241
|
|
222
242
|
# Returns true if the SDK is initialized.
|
@@ -287,6 +307,7 @@ module Sentry
|
|
287
307
|
#
|
288
308
|
# @return [void]
|
289
309
|
def clone_hub_to_current_thread
|
310
|
+
return unless initialized?
|
290
311
|
Thread.current.thread_variable_set(THREAD_LOCAL, get_main_hub.clone)
|
291
312
|
end
|
292
313
|
|
@@ -360,6 +381,25 @@ module Sentry
|
|
360
381
|
get_current_hub.capture_exception(exception, **options, &block)
|
361
382
|
end
|
362
383
|
|
384
|
+
# Takes a block and evaluates it. If the block raised an exception, it reports the exception to Sentry and re-raises it.
|
385
|
+
# If the block ran without exception, it returns the evaluation result.
|
386
|
+
#
|
387
|
+
# @example
|
388
|
+
# Sentry.with_exception_captured do
|
389
|
+
# 1/1 #=> 1 will be returned
|
390
|
+
# end
|
391
|
+
#
|
392
|
+
# Sentry.with_exception_captured do
|
393
|
+
# 1/0 #=> ZeroDivisionError will be reported and re-raised
|
394
|
+
# end
|
395
|
+
#
|
396
|
+
def with_exception_captured(**options, &block)
|
397
|
+
yield
|
398
|
+
rescue Exception => e
|
399
|
+
capture_exception(e, **options)
|
400
|
+
raise
|
401
|
+
end
|
402
|
+
|
363
403
|
# Takes a message string and reports it to Sentry via the currently active hub.
|
364
404
|
#
|
365
405
|
# @yieldparam scope [Scope]
|
data/sentry-ruby-core.gemspec
CHANGED
@@ -18,9 +18,6 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.metadata["source_code_uri"] = spec.homepage
|
19
19
|
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/master/CHANGELOG.md"
|
20
20
|
|
21
|
-
spec.
|
22
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
-
spec.require_paths = ["lib"]
|
24
|
-
|
21
|
+
spec.add_dependency "sentry-ruby", Sentry::VERSION
|
25
22
|
spec.add_dependency "concurrent-ruby"
|
26
23
|
end
|
data/sentry-ruby.gemspec
CHANGED
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.metadata["source_code_uri"] = spec.homepage
|
18
18
|
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/master/CHANGELOG.md"
|
19
19
|
|
20
|
-
spec.
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
21
22
|
spec.add_dependency "concurrent-ruby", '~> 1.0', '>= 1.0.2'
|
22
23
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
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.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sentry Team
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-07-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: sentry-ruby
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 5.4.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 5.4.0
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: concurrent-ruby
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +94,7 @@ files:
|
|
80
94
|
- lib/sentry/session.rb
|
81
95
|
- lib/sentry/session_flusher.rb
|
82
96
|
- lib/sentry/span.rb
|
97
|
+
- lib/sentry/test_helper.rb
|
83
98
|
- lib/sentry/transaction.rb
|
84
99
|
- lib/sentry/transaction_event.rb
|
85
100
|
- lib/sentry/transport.rb
|