sentry-ruby 5.16.1 → 5.19.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 +3 -0
- data/README.md +20 -10
- data/Rakefile +1 -1
- data/bin/console +1 -0
- data/lib/sentry/attachment.rb +42 -0
- data/lib/sentry/background_worker.rb +1 -1
- data/lib/sentry/backpressure_monitor.rb +2 -32
- data/lib/sentry/backtrace.rb +7 -3
- data/lib/sentry/check_in_event.rb +1 -1
- data/lib/sentry/client.rb +59 -9
- data/lib/sentry/configuration.rb +25 -12
- data/lib/sentry/cron/monitor_schedule.rb +1 -1
- data/lib/sentry/dsn.rb +1 -1
- data/lib/sentry/envelope.rb +18 -1
- data/lib/sentry/error_event.rb +2 -2
- data/lib/sentry/event.rb +13 -11
- data/lib/sentry/faraday.rb +77 -0
- data/lib/sentry/graphql.rb +9 -0
- data/lib/sentry/hub.rb +15 -2
- data/lib/sentry/integrable.rb +4 -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 +2 -2
- data/lib/sentry/interfaces/single_exception.rb +6 -4
- data/lib/sentry/interfaces/stacktrace_builder.rb +8 -0
- 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 +43 -0
- data/lib/sentry/metrics.rb +56 -0
- data/lib/sentry/net/http.rb +17 -38
- data/lib/sentry/propagation_context.rb +9 -8
- data/lib/sentry/puma.rb +1 -1
- data/lib/sentry/rack/capture_exceptions.rb +14 -2
- data/lib/sentry/rake.rb +3 -1
- data/lib/sentry/redis.rb +2 -1
- data/lib/sentry/scope.rb +35 -26
- data/lib/sentry/session.rb +2 -2
- data/lib/sentry/session_flusher.rb +6 -38
- data/lib/sentry/span.rb +40 -5
- data/lib/sentry/test_helper.rb +2 -1
- data/lib/sentry/threaded_periodic_worker.rb +39 -0
- data/lib/sentry/transaction.rb +16 -14
- data/lib/sentry/transaction_event.rb +5 -0
- data/lib/sentry/transport/configuration.rb +0 -1
- data/lib/sentry/transport.rb +14 -22
- data/lib/sentry/utils/argument_checking_helper.rb +6 -0
- data/lib/sentry/utils/http_tracing.rb +41 -0
- data/lib/sentry/utils/logging_helper.rb +0 -4
- data/lib/sentry/utils/real_ip.rb +1 -1
- data/lib/sentry/utils/request_id.rb +1 -1
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +34 -3
- data/sentry-ruby.gemspec +12 -5
- metadata +39 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03cdc73e6585f6e0e058539db55db290752a040c0535676687b2a5bce3a4a6a4
|
4
|
+
data.tar.gz: 9480a3870fce66342cffae3f818f220658d8f8368c46d481a27a9bbba9f3c8a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00a09f1d1913abc908247cceb99e813137fe45a9521daa429e385d8fd4d2a6e4c1c6d45c264717de5335dde0d4efc4f2aec9bda2cf5131967ba5878bcb596ee7
|
7
|
+
data.tar.gz: 1f1236a73ed900dc9d38a5448c154dcf4a66ab55eb490528e214f1b3f393a99eccbaa1d303d9c8a3064060b0447c21d6d59f5fdbbcb843203c0e00a4c18adb89
|
data/Gemfile
CHANGED
@@ -15,6 +15,8 @@ gem "puma"
|
|
15
15
|
gem "timecop"
|
16
16
|
gem "stackprof" unless RUBY_PLATFORM == "java"
|
17
17
|
|
18
|
+
gem "graphql", ">= 2.2.6" if RUBY_VERSION.to_f >= 2.7
|
19
|
+
|
18
20
|
gem "benchmark-ips"
|
19
21
|
gem "benchmark_driver"
|
20
22
|
gem "benchmark-ipsa"
|
@@ -22,5 +24,6 @@ gem "benchmark-memory"
|
|
22
24
|
|
23
25
|
gem "yard", github: "lsegal/yard"
|
24
26
|
gem "webrick"
|
27
|
+
gem "faraday"
|
25
28
|
|
26
29
|
eval_gemfile File.expand_path("../Gemfile", __dir__)
|
data/README.md
CHANGED
@@ -13,14 +13,14 @@ _Bad software is everywhere, and we're tired of it. Sentry is on a mission to he
|
|
13
13
|
Sentry SDK for Ruby
|
14
14
|
===========
|
15
15
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
| [](https://rubygems.org/gems/sentry-ruby) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_ruby_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-rails) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_rails_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-sidekiq) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_sidekiq_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-delayed_job) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_delayed_job_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-resque) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_resque_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-opentelemetry) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_opentelemetry_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://rubygems.org/gems/sentry-ruby) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_ruby_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://www.rubydoc.info/gems/sentry-ruby) |
|
19
|
+
| [](https://rubygems.org/gems/sentry-rails) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_rails_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://www.rubydoc.info/gems/sentry-rails) |
|
20
|
+
| [](https://rubygems.org/gems/sentry-sidekiq) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_sidekiq_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://www.rubydoc.info/gems/sentry-sidekiq) |
|
21
|
+
| [](https://rubygems.org/gems/sentry-delayed_job) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_delayed_job_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://www.rubydoc.info/gems/sentry-delayed_job) |
|
22
|
+
| [](https://rubygems.org/gems/sentry-resque) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_resque_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://www.rubydoc.info/gems/sentry-resque) |
|
23
|
+
| [](https://rubygems.org/gems/sentry-opentelemetry) | [](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_opentelemetry_test.yml) | [](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [](https://www.rubydoc.info/gems/sentry-opentelemetry) |
|
24
24
|
|
25
25
|
|
26
26
|
|
@@ -90,7 +90,7 @@ To learn more about sampling transactions, please visit the [official documentat
|
|
90
90
|
- [Sidekiq](https://docs.sentry.io/platforms/ruby/guides/sidekiq/)
|
91
91
|
- [DelayedJob](https://docs.sentry.io/platforms/ruby/guides/delayed_job/)
|
92
92
|
- [Resque](https://docs.sentry.io/platforms/ruby/guides/resque/)
|
93
|
-
- [
|
93
|
+
- [OpenTelemetry](https://docs.sentry.io/platforms/ruby/performance/instrumentation/opentelemetry/)
|
94
94
|
|
95
95
|
### Enriching Events
|
96
96
|
|
@@ -103,6 +103,16 @@ To learn more about sampling transactions, please visit the [official documentat
|
|
103
103
|
|
104
104
|
* [](https://docs.sentry.io/platforms/ruby/)
|
105
105
|
* [](https://forum.sentry.io/c/sdks)
|
106
|
-
* [](https://discord.gg/PXa5Apfe7K)
|
106
|
+
* [](https://discord.gg/PXa5Apfe7K)
|
107
107
|
* [](https://stackoverflow.com/questions/tagged/sentry)
|
108
108
|
* [](https://twitter.com/intent/follow?screen_name=getsentry)
|
109
|
+
|
110
|
+
## Contributing to the SDK
|
111
|
+
|
112
|
+
Please make sure to read the [CONTRIBUTING.md](https://github.com/getsentry/sentry-ruby/blob/master/CONTRIBUTING.md) before making a pull request.
|
113
|
+
|
114
|
+
Thanks to everyone who has contributed to this project so far.
|
115
|
+
|
116
|
+
<a href="https://github.com/getsentry/sentry-ruby/graphs/contributors">
|
117
|
+
<img src="https://contributors-img.web.app/image?repo=getsentry/sentry-ruby" />
|
118
|
+
</a>
|
data/Rakefile
CHANGED
data/bin/console
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
class Attachment
|
5
|
+
PathNotFoundError = Class.new(StandardError)
|
6
|
+
|
7
|
+
attr_reader :bytes, :filename, :path, :content_type
|
8
|
+
|
9
|
+
def initialize(bytes: nil, filename: nil, content_type: nil, path: nil)
|
10
|
+
@bytes = bytes
|
11
|
+
@filename = infer_filename(filename, path)
|
12
|
+
@path = path
|
13
|
+
@content_type = content_type
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_envelope_headers
|
17
|
+
{ type: 'attachment', filename: filename, content_type: content_type, length: payload.bytesize }
|
18
|
+
end
|
19
|
+
|
20
|
+
def payload
|
21
|
+
@payload ||= if bytes
|
22
|
+
bytes
|
23
|
+
else
|
24
|
+
File.binread(path)
|
25
|
+
end
|
26
|
+
rescue Errno::ENOENT
|
27
|
+
raise PathNotFoundError, "Failed to read attachment file, file not found: #{path}"
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def infer_filename(filename, path)
|
33
|
+
return filename if filename
|
34
|
+
|
35
|
+
if path
|
36
|
+
File.basename(path)
|
37
|
+
else
|
38
|
+
raise ArgumentError, "filename or path is required"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -31,7 +31,7 @@ module Sentry
|
|
31
31
|
log_debug("config.background_worker_threads is set to 0, all events will be sent synchronously")
|
32
32
|
Concurrent::ImmediateExecutor.new
|
33
33
|
else
|
34
|
-
log_debug("Initializing the background worker with #{@number_of_threads} threads")
|
34
|
+
log_debug("Initializing the Sentry background worker with #{@number_of_threads} threads")
|
35
35
|
|
36
36
|
executor = Concurrent::ThreadPoolExecutor.new(
|
37
37
|
min_threads: 0,
|
@@ -1,19 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Sentry
|
4
|
-
class BackpressureMonitor
|
5
|
-
include LoggingHelper
|
6
|
-
|
4
|
+
class BackpressureMonitor < ThreadedPeriodicWorker
|
7
5
|
DEFAULT_INTERVAL = 10
|
8
6
|
MAX_DOWNSAMPLE_FACTOR = 10
|
9
7
|
|
10
8
|
def initialize(configuration, client, interval: DEFAULT_INTERVAL)
|
11
|
-
|
9
|
+
super(configuration.logger, interval)
|
12
10
|
@client = client
|
13
|
-
@logger = configuration.logger
|
14
|
-
|
15
|
-
@thread = nil
|
16
|
-
@exited = false
|
17
11
|
|
18
12
|
@healthy = true
|
19
13
|
@downsample_factor = 0
|
@@ -47,29 +41,5 @@ module Sentry
|
|
47
41
|
log_debug("[BackpressureMonitor] health check negative, downsampling with a factor of #{@downsample_factor}")
|
48
42
|
end
|
49
43
|
end
|
50
|
-
|
51
|
-
def kill
|
52
|
-
log_debug("[BackpressureMonitor] killing monitor")
|
53
|
-
|
54
|
-
@exited = true
|
55
|
-
@thread&.kill
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def ensure_thread
|
61
|
-
return if @exited
|
62
|
-
return if @thread&.alive?
|
63
|
-
|
64
|
-
@thread = Thread.new do
|
65
|
-
loop do
|
66
|
-
sleep(@interval)
|
67
|
-
run
|
68
|
-
end
|
69
|
-
end
|
70
|
-
rescue ThreadError
|
71
|
-
log_debug("[BackpressureMonitor] Thread creation failed")
|
72
|
-
@exited = true
|
73
|
-
end
|
74
44
|
end
|
75
45
|
end
|
data/lib/sentry/backtrace.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rubygems"
|
4
|
+
|
3
5
|
module Sentry
|
4
6
|
# @api private
|
5
7
|
class Backtrace
|
@@ -10,7 +12,7 @@ module Sentry
|
|
10
12
|
RUBY_INPUT_FORMAT = /
|
11
13
|
^ \s* (?: [a-zA-Z]: | uri:classloader: )? ([^:]+ | <.*>):
|
12
14
|
(\d+)
|
13
|
-
(?: :in
|
15
|
+
(?: :in\s('|`)([^']+)')?$
|
14
16
|
/x.freeze
|
15
17
|
|
16
18
|
# org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:170)
|
@@ -33,10 +35,10 @@ module Sentry
|
|
33
35
|
# Parses a single line of a given backtrace
|
34
36
|
# @param [String] unparsed_line The raw line from +caller+ or some backtrace
|
35
37
|
# @return [Line] The parsed backtrace line
|
36
|
-
def self.parse(unparsed_line, in_app_pattern)
|
38
|
+
def self.parse(unparsed_line, in_app_pattern = nil)
|
37
39
|
ruby_match = unparsed_line.match(RUBY_INPUT_FORMAT)
|
38
40
|
if ruby_match
|
39
|
-
_, file, number, method = ruby_match.to_a
|
41
|
+
_, file, number, _, method = ruby_match.to_a
|
40
42
|
file.sub!(/\.class$/, RB_EXTENSION)
|
41
43
|
module_name = nil
|
42
44
|
else
|
@@ -55,6 +57,8 @@ module Sentry
|
|
55
57
|
end
|
56
58
|
|
57
59
|
def in_app
|
60
|
+
return false unless in_app_pattern
|
61
|
+
|
58
62
|
if file =~ in_app_pattern
|
59
63
|
true
|
60
64
|
else
|
data/lib/sentry/client.rb
CHANGED
@@ -49,24 +49,35 @@ module Sentry
|
|
49
49
|
return unless configuration.sending_allowed?
|
50
50
|
|
51
51
|
if event.is_a?(ErrorEvent) && !configuration.sample_allowed?
|
52
|
-
transport.record_lost_event(:sample_rate, '
|
52
|
+
transport.record_lost_event(:sample_rate, 'error')
|
53
53
|
return
|
54
54
|
end
|
55
55
|
|
56
56
|
event_type = event.is_a?(Event) ? event.type : event["type"]
|
57
|
+
data_category = Envelope::Item.data_category(event_type)
|
58
|
+
|
59
|
+
is_transaction = event.is_a?(TransactionEvent)
|
60
|
+
spans_before = is_transaction ? event.spans.size : 0
|
61
|
+
|
57
62
|
event = scope.apply_to_event(event, hint)
|
58
63
|
|
59
64
|
if event.nil?
|
60
65
|
log_debug("Discarded event because one of the event processors returned nil")
|
61
|
-
transport.record_lost_event(:event_processor,
|
66
|
+
transport.record_lost_event(:event_processor, data_category)
|
67
|
+
transport.record_lost_event(:event_processor, 'span', num: spans_before + 1) if is_transaction
|
62
68
|
return
|
69
|
+
elsif is_transaction
|
70
|
+
spans_delta = spans_before - event.spans.size
|
71
|
+
transport.record_lost_event(:event_processor, 'span', num: spans_delta) if spans_delta > 0
|
63
72
|
end
|
64
73
|
|
65
74
|
if async_block = configuration.async
|
66
75
|
dispatch_async_event(async_block, event, hint)
|
67
76
|
elsif configuration.background_worker_threads != 0 && hint.fetch(:background, true)
|
68
|
-
|
69
|
-
|
77
|
+
unless dispatch_background_event(event, hint)
|
78
|
+
transport.record_lost_event(:queue_overflow, data_category)
|
79
|
+
transport.record_lost_event(:queue_overflow, 'span', num: spans_before + 1) if is_transaction
|
80
|
+
end
|
70
81
|
else
|
71
82
|
send_event(event, hint)
|
72
83
|
end
|
@@ -77,6 +88,20 @@ module Sentry
|
|
77
88
|
nil
|
78
89
|
end
|
79
90
|
|
91
|
+
# Capture an envelope directly.
|
92
|
+
# @param envelope [Envelope] the envelope to be captured.
|
93
|
+
# @return [void]
|
94
|
+
def capture_envelope(envelope)
|
95
|
+
Sentry.background_worker.perform { send_envelope(envelope) }
|
96
|
+
end
|
97
|
+
|
98
|
+
# Flush pending events to Sentry.
|
99
|
+
# @return [void]
|
100
|
+
def flush
|
101
|
+
transport.flush if configuration.sending_to_dsn_allowed?
|
102
|
+
spotlight_transport.flush if spotlight_transport
|
103
|
+
end
|
104
|
+
|
80
105
|
# Initializes an Event object with the given exception. Returns `nil` if the exception's class is excluded from reporting.
|
81
106
|
# @param exception [Exception] the exception to be reported.
|
82
107
|
# @param hint [Hash] the hint data that'll be passed to `before_send` callback and the scope's event processors.
|
@@ -88,9 +113,10 @@ module Sentry
|
|
88
113
|
return if !ignore_exclusions && !@configuration.exception_class_allowed?(exception)
|
89
114
|
|
90
115
|
integration_meta = Sentry.integrations[hint[:integration]]
|
116
|
+
mechanism = hint.delete(:mechanism) { Mechanism.new }
|
91
117
|
|
92
118
|
ErrorEvent.new(configuration: configuration, integration_meta: integration_meta).tap do |event|
|
93
|
-
event.add_exception_interface(exception)
|
119
|
+
event.add_exception_interface(exception, mechanism: mechanism)
|
94
120
|
event.add_threads_interface(crashed: true)
|
95
121
|
event.level = :error
|
96
122
|
end
|
@@ -151,13 +177,15 @@ module Sentry
|
|
151
177
|
# @!macro send_event
|
152
178
|
def send_event(event, hint = nil)
|
153
179
|
event_type = event.is_a?(Event) ? event.type : event["type"]
|
180
|
+
data_category = Envelope::Item.data_category(event_type)
|
181
|
+
spans_before = event.is_a?(TransactionEvent) ? event.spans.size : 0
|
154
182
|
|
155
183
|
if event_type != TransactionEvent::TYPE && configuration.before_send
|
156
184
|
event = configuration.before_send.call(event, hint)
|
157
185
|
|
158
186
|
if event.nil?
|
159
187
|
log_debug("Discarded event because before_send returned nil")
|
160
|
-
transport.record_lost_event(:before_send,
|
188
|
+
transport.record_lost_event(:before_send, data_category)
|
161
189
|
return
|
162
190
|
end
|
163
191
|
end
|
@@ -168,17 +196,39 @@ module Sentry
|
|
168
196
|
if event.nil?
|
169
197
|
log_debug("Discarded event because before_send_transaction returned nil")
|
170
198
|
transport.record_lost_event(:before_send, 'transaction')
|
199
|
+
transport.record_lost_event(:before_send, 'span', num: spans_before + 1)
|
171
200
|
return
|
201
|
+
else
|
202
|
+
spans_after = event.is_a?(TransactionEvent) ? event.spans.size : 0
|
203
|
+
spans_delta = spans_before - spans_after
|
204
|
+
transport.record_lost_event(:before_send, 'span', num: spans_delta) if spans_delta > 0
|
172
205
|
end
|
173
206
|
end
|
174
207
|
|
175
|
-
transport.send_event(event)
|
176
|
-
spotlight_transport
|
208
|
+
transport.send_event(event) if configuration.sending_to_dsn_allowed?
|
209
|
+
spotlight_transport.send_event(event) if spotlight_transport
|
177
210
|
|
178
211
|
event
|
179
212
|
rescue => e
|
180
213
|
log_error("Event sending failed", e, debug: configuration.debug)
|
181
|
-
transport.record_lost_event(:network_error,
|
214
|
+
transport.record_lost_event(:network_error, data_category)
|
215
|
+
transport.record_lost_event(:network_error, 'span', num: spans_before + 1) if event.is_a?(TransactionEvent)
|
216
|
+
raise
|
217
|
+
end
|
218
|
+
|
219
|
+
# Send an envelope directly to Sentry.
|
220
|
+
# @param envelope [Envelope] the envelope to be sent.
|
221
|
+
# @return [void]
|
222
|
+
def send_envelope(envelope)
|
223
|
+
transport.send_envelope(envelope) if configuration.sending_to_dsn_allowed?
|
224
|
+
spotlight_transport.send_envelope(envelope) if spotlight_transport
|
225
|
+
rescue => e
|
226
|
+
log_error("Envelope sending failed", e, debug: configuration.debug)
|
227
|
+
|
228
|
+
envelope.items.map(&:data_category).each do |data_category|
|
229
|
+
transport.record_lost_event(:network_error, data_category)
|
230
|
+
end
|
231
|
+
|
182
232
|
raise
|
183
233
|
end
|
184
234
|
|
data/lib/sentry/configuration.rb
CHANGED
@@ -8,6 +8,7 @@ require "sentry/dsn"
|
|
8
8
|
require "sentry/release_detector"
|
9
9
|
require "sentry/transport/configuration"
|
10
10
|
require "sentry/cron/configuration"
|
11
|
+
require "sentry/metrics/configuration"
|
11
12
|
require "sentry/linecache"
|
12
13
|
require "sentry/interfaces/stacktrace_builder"
|
13
14
|
|
@@ -235,6 +236,10 @@ module Sentry
|
|
235
236
|
# @return [Cron::Configuration]
|
236
237
|
attr_reader :cron
|
237
238
|
|
239
|
+
# Metrics related configuration.
|
240
|
+
# @return [Metrics::Configuration]
|
241
|
+
attr_reader :metrics
|
242
|
+
|
238
243
|
# Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
|
239
244
|
# @return [Float, nil]
|
240
245
|
attr_reader :traces_sample_rate
|
@@ -311,11 +316,11 @@ module Sentry
|
|
311
316
|
'Sinatra::NotFound'
|
312
317
|
].freeze
|
313
318
|
|
314
|
-
RACK_ENV_WHITELIST_DEFAULT = %w
|
319
|
+
RACK_ENV_WHITELIST_DEFAULT = %w[
|
315
320
|
REMOTE_ADDR
|
316
321
|
SERVER_NAME
|
317
322
|
SERVER_PORT
|
318
|
-
|
323
|
+
].freeze
|
319
324
|
|
320
325
|
HEROKU_DYNO_METADATA_MESSAGE = "You are running on Heroku but haven't enabled Dyno Metadata. For Sentry's "\
|
321
326
|
"release detection to work correctly, please run `heroku labs:enable runtime-dyno-metadata`".freeze
|
@@ -328,7 +333,7 @@ module Sentry
|
|
328
333
|
|
329
334
|
PROPAGATION_TARGETS_MATCH_ALL = /.*/.freeze
|
330
335
|
|
331
|
-
DEFAULT_PATCHES = %i
|
336
|
+
DEFAULT_PATCHES = %i[redis puma http].freeze
|
332
337
|
|
333
338
|
class << self
|
334
339
|
# Post initialization callbacks are called at the end of initialization process
|
@@ -337,7 +342,7 @@ module Sentry
|
|
337
342
|
@post_initialization_callbacks ||= []
|
338
343
|
end
|
339
344
|
|
340
|
-
|
345
|
+
# allow extensions to add their hooks to the Configuration class
|
341
346
|
def add_post_initialization_callback(&block)
|
342
347
|
post_initialization_callbacks << block
|
343
348
|
end
|
@@ -346,7 +351,7 @@ module Sentry
|
|
346
351
|
def initialize
|
347
352
|
self.app_dirs_pattern = nil
|
348
353
|
self.debug = false
|
349
|
-
self.background_worker_threads =
|
354
|
+
self.background_worker_threads = (processor_count / 2.0).ceil
|
350
355
|
self.background_worker_max_queue = BackgroundWorker::DEFAULT_MAX_QUEUE
|
351
356
|
self.backtrace_cleanup_callback = nil
|
352
357
|
self.max_breadcrumbs = BreadcrumbBuffer::DEFAULT_SIZE
|
@@ -386,6 +391,7 @@ module Sentry
|
|
386
391
|
|
387
392
|
@transport = Transport::Configuration.new
|
388
393
|
@cron = Cron::Configuration.new
|
394
|
+
@metrics = Metrics::Configuration.new
|
389
395
|
@gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
390
396
|
|
391
397
|
run_post_initialization_callbacks
|
@@ -479,9 +485,13 @@ module Sentry
|
|
479
485
|
end
|
480
486
|
|
481
487
|
def sending_allowed?
|
488
|
+
spotlight || sending_to_dsn_allowed?
|
489
|
+
end
|
490
|
+
|
491
|
+
def sending_to_dsn_allowed?
|
482
492
|
@errors = []
|
483
493
|
|
484
|
-
|
494
|
+
valid? && capture_in_environment?
|
485
495
|
end
|
486
496
|
|
487
497
|
def sample_allowed?
|
@@ -490,6 +500,10 @@ module Sentry
|
|
490
500
|
Random.rand < sample_rate
|
491
501
|
end
|
492
502
|
|
503
|
+
def session_tracking?
|
504
|
+
auto_session_tracking && enabled_in_current_env?
|
505
|
+
end
|
506
|
+
|
493
507
|
def exception_class_allowed?(exc)
|
494
508
|
if exc.is_a?(Sentry::Error)
|
495
509
|
# Try to prevent error reporting loops
|
@@ -566,12 +580,6 @@ module Sentry
|
|
566
580
|
|
567
581
|
private
|
568
582
|
|
569
|
-
def check_callable!(name, value)
|
570
|
-
unless value == nil || value.respond_to?(:call)
|
571
|
-
raise ArgumentError, "#{name} must be callable (or nil to disable)"
|
572
|
-
end
|
573
|
-
end
|
574
|
-
|
575
583
|
def init_dsn(dsn_string)
|
576
584
|
return if dsn_string.nil? || dsn_string.empty?
|
577
585
|
|
@@ -646,5 +654,10 @@ module Sentry
|
|
646
654
|
instance_eval(&hook)
|
647
655
|
end
|
648
656
|
end
|
657
|
+
|
658
|
+
def processor_count
|
659
|
+
available_processor_count = Concurrent.available_processor_count if Concurrent.respond_to?(:available_processor_count)
|
660
|
+
available_processor_count || Concurrent.processor_count
|
661
|
+
end
|
649
662
|
end
|
650
663
|
end
|
data/lib/sentry/dsn.rb
CHANGED
@@ -5,7 +5,7 @@ require "uri"
|
|
5
5
|
module Sentry
|
6
6
|
class DSN
|
7
7
|
PORT_MAP = { 'http' => 80, 'https' => 443 }.freeze
|
8
|
-
REQUIRED_ATTRIBUTES = %w
|
8
|
+
REQUIRED_ATTRIBUTES = %w[host path public_key project_id].freeze
|
9
9
|
|
10
10
|
attr_reader :scheme, :secret_key, :port, *REQUIRED_ATTRIBUTES
|
11
11
|
|
data/lib/sentry/envelope.rb
CHANGED
@@ -18,8 +18,25 @@ module Sentry
|
|
18
18
|
@headers[:type] || 'event'
|
19
19
|
end
|
20
20
|
|
21
|
+
# rate limits and client reports use the data_category rather than envelope item type
|
22
|
+
def self.data_category(type)
|
23
|
+
case type
|
24
|
+
when 'session', 'attachment', 'transaction', 'profile', 'span' then type
|
25
|
+
when 'sessions' then 'session'
|
26
|
+
when 'check_in' then 'monitor'
|
27
|
+
when 'statsd', 'metric_meta' then 'metric_bucket'
|
28
|
+
when 'event' then 'error'
|
29
|
+
when 'client_report' then 'internal'
|
30
|
+
else 'default'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def data_category
|
35
|
+
self.class.data_category(type)
|
36
|
+
end
|
37
|
+
|
21
38
|
def to_s
|
22
|
-
[JSON.generate(@headers), JSON.generate(@payload)].join("\n")
|
39
|
+
[JSON.generate(@headers), @payload.is_a?(String) ? @payload : JSON.generate(@payload)].join("\n")
|
23
40
|
end
|
24
41
|
|
25
42
|
def serialize
|
data/lib/sentry/error_event.rb
CHANGED
@@ -27,12 +27,12 @@ module Sentry
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# @!visibility private
|
30
|
-
def add_exception_interface(exception)
|
30
|
+
def add_exception_interface(exception, mechanism:)
|
31
31
|
if exception.respond_to?(:sentry_context)
|
32
32
|
@extra.merge!(exception.sentry_context)
|
33
33
|
end
|
34
34
|
|
35
|
-
@exception = Sentry::ExceptionInterface.build(exception: exception, stacktrace_builder: @stacktrace_builder)
|
35
|
+
@exception = Sentry::ExceptionInterface.build(exception: exception, stacktrace_builder: @stacktrace_builder, mechanism: mechanism)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
data/lib/sentry/event.rb
CHANGED
@@ -14,16 +14,16 @@ module Sentry
|
|
14
14
|
class Event
|
15
15
|
TYPE = "event"
|
16
16
|
# These are readable attributes.
|
17
|
-
SERIALIZEABLE_ATTRIBUTES = %i
|
17
|
+
SERIALIZEABLE_ATTRIBUTES = %i[
|
18
18
|
event_id level timestamp
|
19
19
|
release environment server_name modules
|
20
20
|
message user tags contexts extra
|
21
21
|
fingerprint breadcrumbs transaction transaction_info
|
22
22
|
platform sdk type
|
23
|
-
|
23
|
+
]
|
24
24
|
|
25
25
|
# These are writable attributes.
|
26
|
-
WRITER_ATTRIBUTES = SERIALIZEABLE_ATTRIBUTES - %i
|
26
|
+
WRITER_ATTRIBUTES = SERIALIZEABLE_ATTRIBUTES - %i[type timestamp level]
|
27
27
|
|
28
28
|
MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
|
29
29
|
|
@@ -42,6 +42,9 @@ module Sentry
|
|
42
42
|
# @return [Hash, nil]
|
43
43
|
attr_accessor :dynamic_sampling_context
|
44
44
|
|
45
|
+
# @return [Array<Attachment>]
|
46
|
+
attr_accessor :attachments
|
47
|
+
|
45
48
|
# @param configuration [Configuration]
|
46
49
|
# @param integration_meta [Hash, nil]
|
47
50
|
# @param message [String, nil]
|
@@ -57,6 +60,7 @@ module Sentry
|
|
57
60
|
@extra = {}
|
58
61
|
@contexts = {}
|
59
62
|
@tags = {}
|
63
|
+
@attachments = []
|
60
64
|
|
61
65
|
@fingerprint = []
|
62
66
|
@dynamic_sampling_context = nil
|
@@ -104,9 +108,7 @@ module Sentry
|
|
104
108
|
unless request || env.empty?
|
105
109
|
add_request_interface(env)
|
106
110
|
|
107
|
-
if @send_default_pii
|
108
|
-
user[:ip_address] = calculate_real_ip_from_rack(env)
|
109
|
-
end
|
111
|
+
user[:ip_address] ||= calculate_real_ip_from_rack(env) if @send_default_pii
|
110
112
|
|
111
113
|
if request_id = Utils::RequestId.read_from(env)
|
112
114
|
tags[:request_id] = request_id
|
@@ -145,11 +147,11 @@ module Sentry
|
|
145
147
|
# REMOTE_ADDR to determine the Event IP, and must use other headers instead.
|
146
148
|
def calculate_real_ip_from_rack(env)
|
147
149
|
Utils::RealIp.new(
|
148
|
-
:
|
149
|
-
:
|
150
|
-
:
|
151
|
-
:
|
152
|
-
:
|
150
|
+
remote_addr: env["REMOTE_ADDR"],
|
151
|
+
client_ip: env["HTTP_CLIENT_IP"],
|
152
|
+
real_ip: env["HTTP_X_REAL_IP"],
|
153
|
+
forwarded_for: env["HTTP_X_FORWARDED_FOR"],
|
154
|
+
trusted_proxies: @trusted_proxies
|
153
155
|
).calculate_ip
|
154
156
|
end
|
155
157
|
end
|