sentry-ruby-core 4.7.1 → 4.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -2
- data/LICENSE.txt +1 -1
- data/README.md +7 -7
- data/bin/console +5 -1
- data/lib/sentry/background_worker.rb +30 -2
- data/lib/sentry/breadcrumb/sentry_logger.rb +2 -0
- data/lib/sentry/breadcrumb.rb +2 -0
- data/lib/sentry/breadcrumb_buffer.rb +2 -0
- data/lib/sentry/client.rb +13 -1
- data/lib/sentry/configuration.rb +57 -77
- 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 +25 -0
- data/lib/sentry/event.rb +5 -0
- data/lib/sentry/exceptions.rb +2 -0
- data/lib/sentry/hub.rb +13 -4
- data/lib/sentry/integrable.rb +2 -0
- data/lib/sentry/interface.rb +2 -0
- data/lib/sentry/interfaces/exception.rb +2 -0
- data/lib/sentry/interfaces/single_exception.rb +31 -0
- data/lib/sentry/interfaces/stacktrace.rb +10 -0
- data/lib/sentry/interfaces/stacktrace_builder.rb +2 -0
- data/lib/sentry/interfaces/threads.rb +2 -0
- data/lib/sentry/linecache.rb +2 -0
- data/lib/sentry/net/http.rb +2 -0
- data/lib/sentry/rack/capture_exceptions.rb +2 -0
- data/lib/sentry/rack.rb +2 -0
- data/lib/sentry/rake.rb +4 -4
- data/lib/sentry/release_detector.rb +38 -0
- data/lib/sentry/scope.rb +8 -4
- data/lib/sentry/span.rb +1 -0
- data/lib/sentry/transaction.rb +6 -1
- data/lib/sentry/transport/configuration.rb +2 -0
- data/lib/sentry/transport/dummy_transport.rb +2 -0
- data/lib/sentry/transport/http_transport.rb +6 -4
- data/lib/sentry/transport.rb +77 -19
- data/lib/sentry/utils/argument_checking_helper.rb +2 -0
- data/lib/sentry/utils/custom_inspection.rb +14 -0
- data/lib/sentry/utils/exception_cause_chain.rb +10 -10
- data/lib/sentry/utils/logging_helper.rb +2 -0
- 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 +26 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0d62d3133d461116b39ce7e822a3cc523c378417eafade8b3a904f76bce5289
|
4
|
+
data.tar.gz: 4ae280d6e7d88107e7f34f0794d266182d1c801407373023293c38db038aae50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8027f22238a8012bb1aca95d528cb479e287a5b6b17269c9789056d6959f33cab558fac3166147b82b2bda7ee6ad87f4d484ad83634d41804bf198ea7fddd7b2
|
7
|
+
data.tar.gz: ea6681465bf4f538139b0ba6057ea34dec7cb848e77be48ca65c5d7ee5080c492f324dda7903f40d1db275d4bea4f3887048ebf144d7748d02be35314e5fb977
|
data/Gemfile
CHANGED
@@ -10,10 +10,12 @@ gem "rspec", "~> 3.0"
|
|
10
10
|
gem "rspec-retry"
|
11
11
|
gem "webmock"
|
12
12
|
gem "timecop"
|
13
|
-
gem
|
13
|
+
gem 'simplecov'
|
14
|
+
gem "simplecov-cobertura", "~> 1.4"
|
15
|
+
gem "rexml"
|
14
16
|
|
15
17
|
gem "object_tracer"
|
16
|
-
gem "debug", github: "ruby/debug" if RUBY_VERSION.to_f >= 2.6
|
18
|
+
gem "debug", github: "ruby/debug", platform: :ruby if RUBY_VERSION.to_f >= 2.6
|
17
19
|
gem "pry"
|
18
20
|
|
19
21
|
gem "benchmark-ips"
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -10,13 +10,13 @@ _Bad software is everywhere, and we're tired of it. Sentry is on a mission to he
|
|
10
10
|
Sentry SDK for Ruby
|
11
11
|
===========
|
12
12
|
|
13
|
-
| current version | build | coverage | downloads |
|
14
|
-
| --- | ----- | -------- | --------- |
|
15
|
-
| [![Gem Version](https://img.shields.io/gem/v/sentry-ruby?label=sentry-ruby)](https://rubygems.org/gems/sentry-ruby) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-ruby%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_ruby_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-ruby.svg)](https://rubygems.org/gems/sentry-ruby/) |
|
16
|
-
| [![Gem Version](https://img.shields.io/gem/v/sentry-rails?label=sentry-rails)](https://rubygems.org/gems/sentry-rails) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-rails%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_rails_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-rails.svg)](https://rubygems.org/gems/sentry-rails/) |
|
17
|
-
| [![Gem Version](https://img.shields.io/gem/v/sentry-sidekiq?label=sentry-sidekiq)](https://rubygems.org/gems/sentry-sidekiq) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-sidekiq%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_sidekiq_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-sidekiq.svg)](https://rubygems.org/gems/sentry-sidekiq/) |
|
18
|
-
| [![Gem Version](https://img.shields.io/gem/v/sentry-delayed_job?label=sentry-delayed_job)](https://rubygems.org/gems/sentry-delayed_job) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-delayed_job%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_delayed_job_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-delayed_job.svg)](https://rubygems.org/gems/sentry-delayed_job/) |
|
19
|
-
| [![Gem Version](https://img.shields.io/gem/v/sentry-resque?label=sentry-resque)](https://rubygems.org/gems/sentry-resque) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-resque%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_resque_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-resque.svg)](https://rubygems.org/gems/sentry-resque/) |
|
13
|
+
| current version | build | coverage | downloads |
|
14
|
+
| --- | ----- | -------- | --------- |
|
15
|
+
| [![Gem Version](https://img.shields.io/gem/v/sentry-ruby?label=sentry-ruby)](https://rubygems.org/gems/sentry-ruby) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-ruby%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_ruby_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-ruby.svg)](https://rubygems.org/gems/sentry-ruby/) |
|
16
|
+
| [![Gem Version](https://img.shields.io/gem/v/sentry-rails?label=sentry-rails)](https://rubygems.org/gems/sentry-rails) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-rails%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_rails_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-rails.svg)](https://rubygems.org/gems/sentry-rails/) |
|
17
|
+
| [![Gem Version](https://img.shields.io/gem/v/sentry-sidekiq?label=sentry-sidekiq)](https://rubygems.org/gems/sentry-sidekiq) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-sidekiq%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_sidekiq_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-sidekiq.svg)](https://rubygems.org/gems/sentry-sidekiq/) |
|
18
|
+
| [![Gem Version](https://img.shields.io/gem/v/sentry-delayed_job?label=sentry-delayed_job)](https://rubygems.org/gems/sentry-delayed_job) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-delayed_job%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_delayed_job_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-delayed_job.svg)](https://rubygems.org/gems/sentry-delayed_job/) |
|
19
|
+
| [![Gem Version](https://img.shields.io/gem/v/sentry-resque?label=sentry-resque)](https://rubygems.org/gems/sentry-resque) | [![Build Status](https://github.com/getsentry/sentry-ruby/workflows/sentry-resque%20Test/badge.svg)](https://github.com/getsentry/sentry-ruby/actions/workflows/sentry_resque_test.yml) | [![Coverage Status](https://img.shields.io/codecov/c/github/getsentry/sentry-ruby/master?logo=codecov)](https://codecov.io/gh/getsentry/sentry-ruby/branch/master) | [![Downloads](https://img.shields.io/gem/dt/sentry-resque.svg)](https://rubygems.org/gems/sentry-resque/) |
|
20
20
|
|
21
21
|
|
22
22
|
|
data/bin/console
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require "bundler/setup"
|
4
|
-
require "sentry
|
4
|
+
require "sentry-ruby"
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +10,9 @@ require "sentry/ruby"
|
|
10
10
|
# require "pry"
|
11
11
|
# Pry.start
|
12
12
|
|
13
|
+
# Sentry.init do |config|
|
14
|
+
# config.dsn = 'https://2fb45f003d054a7ea47feb45898f7649@o447951.ingest.sentry.io/5434472'
|
15
|
+
# end
|
16
|
+
|
13
17
|
require "irb"
|
14
18
|
IRB.start(__FILE__)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "concurrent/executor/thread_pool_executor"
|
2
4
|
require "concurrent/executor/immediate_executor"
|
3
5
|
require "concurrent/configuration"
|
@@ -7,11 +9,15 @@ module Sentry
|
|
7
9
|
include LoggingHelper
|
8
10
|
|
9
11
|
attr_reader :max_queue, :number_of_threads, :logger
|
12
|
+
attr_accessor :shutdown_timeout
|
10
13
|
|
11
14
|
def initialize(configuration)
|
12
15
|
@max_queue = 30
|
16
|
+
@shutdown_timeout = 1
|
13
17
|
@number_of_threads = configuration.background_worker_threads
|
14
18
|
@logger = configuration.logger
|
19
|
+
@debug = configuration.debug
|
20
|
+
@shutdown_callback = nil
|
15
21
|
|
16
22
|
@executor =
|
17
23
|
if configuration.async
|
@@ -23,19 +29,41 @@ module Sentry
|
|
23
29
|
else
|
24
30
|
log_debug("initialized a background worker with #{@number_of_threads} threads")
|
25
31
|
|
26
|
-
Concurrent::ThreadPoolExecutor.new(
|
32
|
+
executor = Concurrent::ThreadPoolExecutor.new(
|
27
33
|
min_threads: 0,
|
28
34
|
max_threads: @number_of_threads,
|
29
35
|
max_queue: @max_queue,
|
30
36
|
fallback_policy: :discard
|
31
37
|
)
|
38
|
+
|
39
|
+
@shutdown_callback = proc do
|
40
|
+
executor.shutdown
|
41
|
+
executor.wait_for_termination(@shutdown_timeout)
|
42
|
+
end
|
43
|
+
|
44
|
+
executor
|
32
45
|
end
|
33
46
|
end
|
34
47
|
|
48
|
+
# if you want to monkey-patch this method, please override `_perform` instead
|
35
49
|
def perform(&block)
|
36
50
|
@executor.post do
|
37
|
-
|
51
|
+
begin
|
52
|
+
_perform(&block)
|
53
|
+
rescue Exception => e
|
54
|
+
log_error("exception happened in background worker", e, debug: @debug)
|
55
|
+
end
|
38
56
|
end
|
39
57
|
end
|
58
|
+
|
59
|
+
def shutdown
|
60
|
+
@shutdown_callback&.call
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def _perform(&block)
|
66
|
+
block.call
|
67
|
+
end
|
40
68
|
end
|
41
69
|
end
|
data/lib/sentry/breadcrumb.rb
CHANGED
data/lib/sentry/client.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "sentry/transport"
|
2
4
|
|
3
5
|
module Sentry
|
@@ -26,17 +28,25 @@ module Sentry
|
|
26
28
|
def capture_event(event, scope, hint = {})
|
27
29
|
return unless configuration.sending_allowed?
|
28
30
|
|
31
|
+
unless event.is_a?(TransactionEvent) || configuration.sample_allowed?
|
32
|
+
transport.record_lost_event(:sample_rate, 'event')
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
event_type = event.is_a?(Event) ? event.type : event["type"]
|
29
37
|
event = scope.apply_to_event(event, hint)
|
30
38
|
|
31
39
|
if event.nil?
|
32
40
|
log_info("Discarded event because one of the event processors returned nil")
|
41
|
+
transport.record_lost_event(:event_processor, event_type)
|
33
42
|
return
|
34
43
|
end
|
35
44
|
|
36
45
|
if async_block = configuration.async
|
37
46
|
dispatch_async_event(async_block, event, hint)
|
38
47
|
elsif configuration.background_worker_threads != 0 && hint.fetch(:background, true)
|
39
|
-
dispatch_background_event(event, hint)
|
48
|
+
queued = dispatch_background_event(event, hint)
|
49
|
+
transport.record_lost_event(:queue_overflow, event_type) unless queued
|
40
50
|
else
|
41
51
|
send_event(event, hint)
|
42
52
|
end
|
@@ -84,6 +94,7 @@ module Sentry
|
|
84
94
|
|
85
95
|
if event.nil?
|
86
96
|
log_info("Discarded event because before_send returned nil")
|
97
|
+
transport.record_lost_event(:before_send, 'event')
|
87
98
|
return
|
88
99
|
end
|
89
100
|
end
|
@@ -97,6 +108,7 @@ module Sentry
|
|
97
108
|
|
98
109
|
event_info = Event.get_log_message(event.to_hash)
|
99
110
|
log_info("Unreported #{loggable_event_type}: #{event_info}")
|
111
|
+
transport.record_lost_event(:network_error, event_type)
|
100
112
|
raise
|
101
113
|
end
|
102
114
|
|
data/lib/sentry/configuration.rb
CHANGED
@@ -1,13 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "concurrent/utility/processor_counter"
|
2
4
|
|
3
5
|
require "sentry/utils/exception_cause_chain"
|
6
|
+
require 'sentry/utils/custom_inspection'
|
4
7
|
require "sentry/dsn"
|
8
|
+
require "sentry/release_detector"
|
5
9
|
require "sentry/transport/configuration"
|
6
10
|
require "sentry/linecache"
|
7
11
|
require "sentry/interfaces/stacktrace_builder"
|
8
12
|
|
9
13
|
module Sentry
|
10
14
|
class Configuration
|
15
|
+
include CustomInspection
|
11
16
|
include LoggingHelper
|
12
17
|
# Directories to be recognized as part of your app. e.g. if you
|
13
18
|
# have an `engines` dir at the root of your project, you may want
|
@@ -63,6 +68,9 @@ module Sentry
|
|
63
68
|
# - :active_support_logger
|
64
69
|
attr_reader :breadcrumbs_logger
|
65
70
|
|
71
|
+
# Whether to capture local variables from the raised exception's frame. Default is false.
|
72
|
+
attr_accessor :capture_exception_frame_locals
|
73
|
+
|
66
74
|
# Max number of breadcrumbs a breadcrumb buffer can hold
|
67
75
|
attr_accessor :max_breadcrumbs
|
68
76
|
|
@@ -104,7 +112,7 @@ module Sentry
|
|
104
112
|
|
105
113
|
# Project directory root for in_app detection. Could be Rails root, etc.
|
106
114
|
# Set automatically for Rails.
|
107
|
-
|
115
|
+
attr_accessor :project_root
|
108
116
|
|
109
117
|
# Insert sentry-trace to outgoing requests' headers
|
110
118
|
attr_accessor :propagate_traces
|
@@ -154,6 +162,10 @@ module Sentry
|
|
154
162
|
# ```
|
155
163
|
attr_accessor :traces_sampler
|
156
164
|
|
165
|
+
# Send diagnostic client reports about dropped events, true by default
|
166
|
+
# tries to attach to an existing envelope max once every 30s
|
167
|
+
attr_accessor :send_client_reports
|
168
|
+
|
157
169
|
# these are not config options
|
158
170
|
attr_reader :errors, :gem_specs
|
159
171
|
|
@@ -177,17 +189,21 @@ module Sentry
|
|
177
189
|
|
178
190
|
LOG_PREFIX = "** [Sentry] ".freeze
|
179
191
|
MODULE_SEPARATOR = "::".freeze
|
192
|
+
SKIP_INSPECTION_ATTRIBUTES = [:@linecache, :@stacktrace_builder]
|
180
193
|
|
181
194
|
# Post initialization callbacks are called at the end of initialization process
|
182
195
|
# allowing extending the configuration of sentry-ruby by multiple extensions
|
183
196
|
@@post_initialization_callbacks = []
|
184
197
|
|
185
198
|
def initialize
|
199
|
+
self.app_dirs_pattern = nil
|
186
200
|
self.debug = false
|
187
201
|
self.background_worker_threads = Concurrent.processor_count
|
202
|
+
self.backtrace_cleanup_callback = nil
|
188
203
|
self.max_breadcrumbs = BreadcrumbBuffer::DEFAULT_SIZE
|
189
204
|
self.breadcrumbs_logger = []
|
190
205
|
self.context_lines = 3
|
206
|
+
self.capture_exception_frame_locals = false
|
191
207
|
self.environment = environment_from_env
|
192
208
|
self.enabled_environments = []
|
193
209
|
self.exclude_loggers = []
|
@@ -202,12 +218,15 @@ module Sentry
|
|
202
218
|
self.send_modules = true
|
203
219
|
self.send_default_pii = false
|
204
220
|
self.skip_rake_integration = false
|
221
|
+
self.send_client_reports = true
|
205
222
|
self.trusted_proxies = []
|
206
223
|
self.dsn = ENV['SENTRY_DSN']
|
207
224
|
self.server_name = server_name_from_env
|
208
225
|
|
209
|
-
self.before_send =
|
226
|
+
self.before_send = nil
|
210
227
|
self.rack_env_whitelist = RACK_ENV_WHITELIST_DEFAULT
|
228
|
+
self.traces_sample_rate = nil
|
229
|
+
self.traces_sampler = nil
|
211
230
|
|
212
231
|
@transport = Transport::Configuration.new
|
213
232
|
@gem_specs = Hash[Gem::Specification.map { |spec| [spec.name, spec.version.to_s] }] if Gem::Specification.respond_to?(:map)
|
@@ -216,18 +235,13 @@ module Sentry
|
|
216
235
|
end
|
217
236
|
|
218
237
|
def dsn=(value)
|
219
|
-
|
220
|
-
|
221
|
-
@dsn = DSN.new(value)
|
238
|
+
@dsn = init_dsn(value)
|
222
239
|
end
|
223
240
|
|
224
241
|
alias server= dsn=
|
225
242
|
|
226
|
-
|
227
243
|
def async=(value)
|
228
|
-
|
229
|
-
raise(ArgumentError, "async must be callable")
|
230
|
-
end
|
244
|
+
check_callable!("async", value)
|
231
245
|
|
232
246
|
@async = value
|
233
247
|
end
|
@@ -246,17 +260,13 @@ module Sentry
|
|
246
260
|
end
|
247
261
|
|
248
262
|
def before_send=(value)
|
249
|
-
|
250
|
-
raise ArgumentError, "before_send must be callable (or false to disable)"
|
251
|
-
end
|
263
|
+
check_callable!("before_send", value)
|
252
264
|
|
253
265
|
@before_send = value
|
254
266
|
end
|
255
267
|
|
256
268
|
def before_breadcrumb=(value)
|
257
|
-
|
258
|
-
raise ArgumentError, "before_breadcrumb must be callable (or nil to disable)"
|
259
|
-
end
|
269
|
+
check_callable!("before_breadcrumb", value)
|
260
270
|
|
261
271
|
@before_breadcrumb = value
|
262
272
|
end
|
@@ -268,9 +278,13 @@ module Sentry
|
|
268
278
|
def sending_allowed?
|
269
279
|
@errors = []
|
270
280
|
|
271
|
-
valid? &&
|
272
|
-
|
273
|
-
|
281
|
+
valid? && capture_in_environment?
|
282
|
+
end
|
283
|
+
|
284
|
+
def sample_allowed?
|
285
|
+
return true if sample_rate == 1.0
|
286
|
+
|
287
|
+
Random.rand < sample_rate
|
274
288
|
end
|
275
289
|
|
276
290
|
def error_messages
|
@@ -278,10 +292,6 @@ module Sentry
|
|
278
292
|
@errors.join(", ")
|
279
293
|
end
|
280
294
|
|
281
|
-
def project_root=(root_dir)
|
282
|
-
@project_root = root_dir
|
283
|
-
end
|
284
|
-
|
285
295
|
def exception_class_allowed?(exc)
|
286
296
|
if exc.is_a?(Sentry::Error)
|
287
297
|
# Try to prevent error reporting loops
|
@@ -316,10 +326,11 @@ module Sentry
|
|
316
326
|
def detect_release
|
317
327
|
return unless sending_allowed?
|
318
328
|
|
319
|
-
self.release ||=
|
320
|
-
|
321
|
-
|
322
|
-
|
329
|
+
self.release ||= ReleaseDetector.detect_release(project_root: project_root, running_on_heroku: running_on_heroku?)
|
330
|
+
|
331
|
+
if running_on_heroku? && release.nil?
|
332
|
+
log_warn(HEROKU_DYNO_METADATA_MESSAGE)
|
333
|
+
end
|
323
334
|
rescue => e
|
324
335
|
log_error("Error detecting release", e, debug: debug)
|
325
336
|
end
|
@@ -335,6 +346,18 @@ module Sentry
|
|
335
346
|
|
336
347
|
private
|
337
348
|
|
349
|
+
def check_callable!(name, value)
|
350
|
+
unless value == nil || value.respond_to?(:call)
|
351
|
+
raise ArgumentError, "#{name} must be callable (or nil to disable)"
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
def init_dsn(dsn_string)
|
356
|
+
return if dsn_string.nil? || dsn_string.empty?
|
357
|
+
|
358
|
+
DSN.new(dsn_string)
|
359
|
+
end
|
360
|
+
|
338
361
|
def excluded_exception?(incoming_exception)
|
339
362
|
excluded_exception_classes.any? do |excluded_exception|
|
340
363
|
matches_exception?(excluded_exception, incoming_exception)
|
@@ -364,37 +387,6 @@ module Sentry
|
|
364
387
|
nil
|
365
388
|
end
|
366
389
|
|
367
|
-
def detect_release_from_heroku
|
368
|
-
return unless running_on_heroku?
|
369
|
-
return if ENV['CI']
|
370
|
-
log_warn(HEROKU_DYNO_METADATA_MESSAGE) && return unless ENV['HEROKU_SLUG_COMMIT']
|
371
|
-
|
372
|
-
ENV['HEROKU_SLUG_COMMIT']
|
373
|
-
end
|
374
|
-
|
375
|
-
def running_on_heroku?
|
376
|
-
File.directory?("/etc/heroku")
|
377
|
-
end
|
378
|
-
|
379
|
-
def detect_release_from_capistrano
|
380
|
-
revision_file = File.join(project_root, 'REVISION')
|
381
|
-
revision_log = File.join(project_root, '..', 'revisions.log')
|
382
|
-
|
383
|
-
if File.exist?(revision_file)
|
384
|
-
File.read(revision_file).strip
|
385
|
-
elsif File.exist?(revision_log)
|
386
|
-
File.open(revision_log).to_a.last.strip.sub(/.*as release ([0-9]+).*/, '\1')
|
387
|
-
end
|
388
|
-
end
|
389
|
-
|
390
|
-
def detect_release_from_git
|
391
|
-
Sentry.sys_command("git rev-parse --short HEAD") if File.directory?(".git")
|
392
|
-
end
|
393
|
-
|
394
|
-
def detect_release_from_env
|
395
|
-
ENV['SENTRY_RELEASE']
|
396
|
-
end
|
397
|
-
|
398
390
|
def capture_in_environment?
|
399
391
|
return true if enabled_in_current_env?
|
400
392
|
|
@@ -411,36 +403,24 @@ module Sentry
|
|
411
403
|
end
|
412
404
|
end
|
413
405
|
|
414
|
-
def sample_allowed?
|
415
|
-
return true if sample_rate == 1.0
|
416
|
-
|
417
|
-
if Random.rand >= sample_rate
|
418
|
-
@errors << "Excluded by random sample"
|
419
|
-
false
|
420
|
-
else
|
421
|
-
true
|
422
|
-
end
|
423
|
-
end
|
424
|
-
|
425
|
-
# Try to resolve the hostname to an FQDN, but fall back to whatever
|
426
|
-
# the load name is.
|
427
|
-
def resolve_hostname
|
428
|
-
Socket.gethostname ||
|
429
|
-
Socket.gethostbyname(hostname).first rescue server_name
|
430
|
-
end
|
431
|
-
|
432
406
|
def environment_from_env
|
433
|
-
ENV['SENTRY_CURRENT_ENV'] || ENV['SENTRY_ENVIRONMENT'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || '
|
407
|
+
ENV['SENTRY_CURRENT_ENV'] || ENV['SENTRY_ENVIRONMENT'] || ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
|
434
408
|
end
|
435
409
|
|
436
410
|
def server_name_from_env
|
437
411
|
if running_on_heroku?
|
438
412
|
ENV['DYNO']
|
439
413
|
else
|
440
|
-
|
414
|
+
# Try to resolve the hostname to an FQDN, but fall back to whatever
|
415
|
+
# the load name is.
|
416
|
+
Socket.gethostname || Socket.gethostbyname(hostname).first rescue server_name
|
441
417
|
end
|
442
418
|
end
|
443
419
|
|
420
|
+
def running_on_heroku?
|
421
|
+
File.directory?("/etc/heroku") && !ENV["CI"]
|
422
|
+
end
|
423
|
+
|
444
424
|
def run_post_initialization_callbacks
|
445
425
|
self.class.post_initialization_callbacks.each do |hook|
|
446
426
|
instance_eval(&hook)
|
data/lib/sentry/dsn.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
class Envelope
|
5
|
+
def initialize(headers)
|
6
|
+
@headers = headers
|
7
|
+
@items = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_item(headers, payload)
|
11
|
+
@items << [headers, payload]
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
payload = @items.map do |item_headers, item_payload|
|
16
|
+
<<~ENVELOPE
|
17
|
+
#{JSON.generate(item_headers)}
|
18
|
+
#{JSON.generate(item_payload)}
|
19
|
+
ENVELOPE
|
20
|
+
end.join("\n")
|
21
|
+
|
22
|
+
"#{JSON.generate(@headers)}\n#{payload}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/sentry/event.rb
CHANGED
@@ -6,6 +6,7 @@ require 'sentry/interface'
|
|
6
6
|
require 'sentry/backtrace'
|
7
7
|
require 'sentry/utils/real_ip'
|
8
8
|
require 'sentry/utils/request_id'
|
9
|
+
require 'sentry/utils/custom_inspection'
|
9
10
|
|
10
11
|
module Sentry
|
11
12
|
class Event
|
@@ -21,6 +22,10 @@ module Sentry
|
|
21
22
|
|
22
23
|
MAX_MESSAGE_SIZE_IN_BYTES = 1024 * 8
|
23
24
|
|
25
|
+
SKIP_INSPECTION_ATTRIBUTES = [:@configuration, :@modules, :@backtrace]
|
26
|
+
|
27
|
+
include CustomInspection
|
28
|
+
|
24
29
|
attr_writer(*WRITER_ATTRIBUTES)
|
25
30
|
attr_reader(*SERIALIZEABLE_ATTRIBUTES)
|
26
31
|
|
data/lib/sentry/exceptions.rb
CHANGED
data/lib/sentry/hub.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "sentry/scope"
|
2
4
|
require "sentry/client"
|
3
5
|
|
@@ -90,10 +92,10 @@ module Sentry
|
|
90
92
|
end
|
91
93
|
|
92
94
|
def capture_exception(exception, **options, &block)
|
93
|
-
return unless current_client
|
94
|
-
|
95
95
|
check_argument_type!(exception, ::Exception)
|
96
96
|
|
97
|
+
return unless current_client
|
98
|
+
|
97
99
|
options[:hint] ||= {}
|
98
100
|
options[:hint][:exception] = exception
|
99
101
|
event = current_client.event_from_exception(exception, options[:hint])
|
@@ -104,6 +106,8 @@ module Sentry
|
|
104
106
|
end
|
105
107
|
|
106
108
|
def capture_message(message, **options, &block)
|
109
|
+
check_argument_type!(message, ::String)
|
110
|
+
|
107
111
|
return unless current_client
|
108
112
|
|
109
113
|
options[:hint] ||= {}
|
@@ -114,10 +118,10 @@ module Sentry
|
|
114
118
|
end
|
115
119
|
|
116
120
|
def capture_event(event, **options, &block)
|
117
|
-
return unless current_client
|
118
|
-
|
119
121
|
check_argument_type!(event, Sentry::Event)
|
120
122
|
|
123
|
+
return unless current_client
|
124
|
+
|
121
125
|
hint = options.delete(:hint) || {}
|
122
126
|
scope = current_scope.dup
|
123
127
|
|
@@ -131,6 +135,11 @@ module Sentry
|
|
131
135
|
|
132
136
|
event = current_client.capture_event(event, scope, hint)
|
133
137
|
|
138
|
+
|
139
|
+
if event && configuration.debug
|
140
|
+
configuration.log_debug(event.to_json_compatible)
|
141
|
+
end
|
142
|
+
|
134
143
|
@last_event_id = event&.event_id
|
135
144
|
event
|
136
145
|
end
|
data/lib/sentry/integrable.rb
CHANGED
data/lib/sentry/interface.rb
CHANGED
@@ -1,5 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sentry/utils/exception_cause_chain"
|
4
|
+
|
1
5
|
module Sentry
|
2
6
|
class SingleExceptionInterface < Interface
|
7
|
+
include CustomInspection
|
8
|
+
|
9
|
+
SKIP_INSPECTION_ATTRIBUTES = [:@stacktrace]
|
10
|
+
PROBLEMATIC_LOCAL_VALUE_REPLACEMENT = "[ignored due to error]".freeze
|
11
|
+
OMISSION_MARK = "...".freeze
|
12
|
+
MAX_LOCAL_BYTES = 1024
|
13
|
+
|
3
14
|
attr_reader :type, :value, :module, :thread_id, :stacktrace
|
4
15
|
|
5
16
|
def initialize(exception:, stacktrace: nil)
|
@@ -20,6 +31,26 @@ module Sentry
|
|
20
31
|
# also see `StacktraceBuilder.build`.
|
21
32
|
def self.build_with_stacktrace(exception:, stacktrace_builder:)
|
22
33
|
stacktrace = stacktrace_builder.build(backtrace: exception.backtrace)
|
34
|
+
|
35
|
+
if locals = exception.instance_variable_get(:@sentry_locals)
|
36
|
+
locals.each do |k, v|
|
37
|
+
locals[k] =
|
38
|
+
begin
|
39
|
+
v = v.inspect unless v.is_a?(String)
|
40
|
+
|
41
|
+
if v.length >= MAX_LOCAL_BYTES
|
42
|
+
v = v.byteslice(0..MAX_LOCAL_BYTES - 1) + OMISSION_MARK
|
43
|
+
end
|
44
|
+
|
45
|
+
v
|
46
|
+
rescue StandardError
|
47
|
+
PROBLEMATIC_LOCAL_VALUE_REPLACEMENT
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
stacktrace.frames.last.vars = locals
|
52
|
+
end
|
53
|
+
|
23
54
|
new(exception: exception, stacktrace: stacktrace)
|
24
55
|
end
|
25
56
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
class StacktraceInterface
|
3
5
|
attr_reader :frames
|
@@ -10,6 +12,10 @@ module Sentry
|
|
10
12
|
{ frames: @frames.map(&:to_hash) }
|
11
13
|
end
|
12
14
|
|
15
|
+
def inspect
|
16
|
+
@frames.map(&:to_s)
|
17
|
+
end
|
18
|
+
|
13
19
|
private
|
14
20
|
|
15
21
|
# Not actually an interface, but I want to use the same style
|
@@ -28,6 +34,10 @@ module Sentry
|
|
28
34
|
@filename = compute_filename
|
29
35
|
end
|
30
36
|
|
37
|
+
def to_s
|
38
|
+
"#{@filename}:#{@lineno}"
|
39
|
+
end
|
40
|
+
|
31
41
|
def compute_filename
|
32
42
|
return if abs_path.nil?
|
33
43
|
|
data/lib/sentry/linecache.rb
CHANGED
data/lib/sentry/net/http.rb
CHANGED
data/lib/sentry/rack.rb
CHANGED
data/lib/sentry/rake.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "rake"
|
2
4
|
require "rake/task"
|
3
5
|
|
@@ -5,7 +7,7 @@ module Sentry
|
|
5
7
|
module Rake
|
6
8
|
module Application
|
7
9
|
def display_error_message(ex)
|
8
|
-
Sentry.capture_exception(ex
|
10
|
+
Sentry.capture_exception(ex) do |scope|
|
9
11
|
task_name = top_level_tasks.join(' ')
|
10
12
|
scope.set_transaction_name(task_name)
|
11
13
|
scope.set_tag("rake_task", task_name)
|
@@ -19,9 +21,7 @@ module Sentry
|
|
19
21
|
def execute(args=nil)
|
20
22
|
return super unless Sentry.initialized? && Sentry.get_current_hub
|
21
23
|
|
22
|
-
|
23
|
-
super
|
24
|
-
end
|
24
|
+
super
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
class ReleaseDetector
|
5
|
+
class << self
|
6
|
+
def detect_release(project_root:, running_on_heroku:)
|
7
|
+
detect_release_from_env ||
|
8
|
+
detect_release_from_git ||
|
9
|
+
detect_release_from_capistrano(project_root) ||
|
10
|
+
detect_release_from_heroku(running_on_heroku)
|
11
|
+
end
|
12
|
+
|
13
|
+
def detect_release_from_heroku(running_on_heroku)
|
14
|
+
return unless running_on_heroku
|
15
|
+
ENV['HEROKU_SLUG_COMMIT']
|
16
|
+
end
|
17
|
+
|
18
|
+
def detect_release_from_capistrano(project_root)
|
19
|
+
revision_file = File.join(project_root, 'REVISION')
|
20
|
+
revision_log = File.join(project_root, '..', 'revisions.log')
|
21
|
+
|
22
|
+
if File.exist?(revision_file)
|
23
|
+
File.read(revision_file).strip
|
24
|
+
elsif File.exist?(revision_log)
|
25
|
+
File.open(revision_log).to_a.last.strip.sub(/.*as release ([0-9]+).*/, '\1')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def detect_release_from_git
|
30
|
+
Sentry.sys_command("git rev-parse --short HEAD") if File.directory?(".git")
|
31
|
+
end
|
32
|
+
|
33
|
+
def detect_release_from_env
|
34
|
+
ENV['SENTRY_RELEASE']
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/sentry/scope.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "sentry/breadcrumb_buffer"
|
2
4
|
require "etc"
|
3
5
|
|
@@ -112,7 +114,7 @@ module Sentry
|
|
112
114
|
end
|
113
115
|
|
114
116
|
def set_extra(key, value)
|
115
|
-
|
117
|
+
set_extras(key => value)
|
116
118
|
end
|
117
119
|
|
118
120
|
def set_tags(tags_hash)
|
@@ -121,17 +123,19 @@ module Sentry
|
|
121
123
|
end
|
122
124
|
|
123
125
|
def set_tag(key, value)
|
124
|
-
|
126
|
+
set_tags(key => value)
|
125
127
|
end
|
126
128
|
|
127
129
|
def set_contexts(contexts_hash)
|
128
130
|
check_argument_type!(contexts_hash, Hash)
|
129
|
-
@contexts.merge!(contexts_hash)
|
131
|
+
@contexts.merge!(contexts_hash) do |key, old, new|
|
132
|
+
new.merge(old)
|
133
|
+
end
|
130
134
|
end
|
131
135
|
|
132
136
|
def set_context(key, value)
|
133
137
|
check_argument_type!(value, Hash)
|
134
|
-
|
138
|
+
set_contexts(key => value)
|
135
139
|
end
|
136
140
|
|
137
141
|
def set_level(level)
|
data/lib/sentry/span.rb
CHANGED
data/lib/sentry/transaction.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
class Transaction < Span
|
3
5
|
SENTRY_TRACE_REGEXP = Regexp.new(
|
@@ -129,7 +131,10 @@ module Sentry
|
|
129
131
|
@name = UNLABELD_NAME
|
130
132
|
end
|
131
133
|
|
132
|
-
|
134
|
+
unless @sampled || @parent_sampled
|
135
|
+
hub.current_client.transport.record_lost_event(:sample_rate, 'transaction')
|
136
|
+
return
|
137
|
+
end
|
133
138
|
|
134
139
|
event = hub.current_client.event_from_transaction(self)
|
135
140
|
hub.capture_event(event)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'faraday'
|
2
4
|
require 'zlib'
|
3
5
|
|
@@ -139,10 +141,10 @@ module Sentry
|
|
139
141
|
end
|
140
142
|
|
141
143
|
def ssl_configuration
|
142
|
-
|
143
|
-
:
|
144
|
-
:
|
145
|
-
)
|
144
|
+
{
|
145
|
+
verify: @transport_configuration.ssl_verification,
|
146
|
+
ca_file: @transport_configuration.ssl_ca_file
|
147
|
+
}.merge(@transport_configuration.ssl || {})
|
146
148
|
end
|
147
149
|
end
|
148
150
|
end
|
data/lib/sentry/transport.rb
CHANGED
@@ -1,22 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "json"
|
2
4
|
require "base64"
|
5
|
+
require "sentry/envelope"
|
3
6
|
|
4
7
|
module Sentry
|
5
8
|
class Transport
|
6
9
|
PROTOCOL_VERSION = '7'
|
7
10
|
USER_AGENT = "sentry-ruby/#{Sentry::VERSION}"
|
11
|
+
CLIENT_REPORT_INTERVAL = 30
|
12
|
+
|
13
|
+
# https://develop.sentry.dev/sdk/client-reports/#envelope-item-payload
|
14
|
+
CLIENT_REPORT_REASONS = [
|
15
|
+
:ratelimit_backoff,
|
16
|
+
:queue_overflow,
|
17
|
+
:cache_overflow, # NA
|
18
|
+
:network_error,
|
19
|
+
:sample_rate,
|
20
|
+
:before_send,
|
21
|
+
:event_processor
|
22
|
+
]
|
8
23
|
|
9
24
|
include LoggingHelper
|
10
25
|
|
11
|
-
|
12
|
-
attr_reader :logger, :rate_limits
|
26
|
+
attr_reader :logger, :rate_limits, :discarded_events, :last_client_report_sent
|
13
27
|
|
14
28
|
def initialize(configuration)
|
15
|
-
@configuration = configuration
|
16
29
|
@logger = configuration.logger
|
17
30
|
@transport_configuration = configuration.transport
|
18
31
|
@dsn = configuration.dsn
|
19
32
|
@rate_limits = {}
|
33
|
+
@send_client_reports = configuration.send_client_reports
|
34
|
+
|
35
|
+
if @send_client_reports
|
36
|
+
@discarded_events = Hash.new(0)
|
37
|
+
@last_client_report_sent = Time.now
|
38
|
+
end
|
20
39
|
end
|
21
40
|
|
22
41
|
def send_data(data, options = {})
|
@@ -27,14 +46,9 @@ module Sentry
|
|
27
46
|
event_hash = event.to_hash
|
28
47
|
item_type = get_item_type(event_hash)
|
29
48
|
|
30
|
-
unless configuration.sending_allowed?
|
31
|
-
log_debug("Envelope [#{item_type}] not sent: #{configuration.error_messages}")
|
32
|
-
|
33
|
-
return
|
34
|
-
end
|
35
|
-
|
36
49
|
if is_rate_limited?(item_type)
|
37
50
|
log_info("Envelope [#{item_type}] not sent: rate limiting")
|
51
|
+
record_lost_event(:ratelimit_backoff, item_type)
|
38
52
|
|
39
53
|
return
|
40
54
|
end
|
@@ -91,20 +105,38 @@ module Sentry
|
|
91
105
|
|
92
106
|
def encode(event)
|
93
107
|
# Convert to hash
|
94
|
-
|
108
|
+
event_payload = event.to_hash
|
109
|
+
event_id = event_payload[:event_id] || event_payload["event_id"]
|
110
|
+
item_type = get_item_type(event_payload)
|
111
|
+
|
112
|
+
envelope = Envelope.new(
|
113
|
+
{
|
114
|
+
event_id: event_id,
|
115
|
+
dsn: @dsn.to_s,
|
116
|
+
sdk: Sentry.sdk_meta,
|
117
|
+
sent_at: Sentry.utc_now.iso8601
|
118
|
+
}
|
119
|
+
)
|
120
|
+
|
121
|
+
envelope.add_item(
|
122
|
+
{ type: item_type, content_type: 'application/json' },
|
123
|
+
event_payload
|
124
|
+
)
|
125
|
+
|
126
|
+
client_report_headers, client_report_payload = fetch_pending_client_report
|
127
|
+
envelope.add_item(client_report_headers, client_report_payload) if client_report_headers
|
95
128
|
|
96
|
-
|
97
|
-
item_type = get_item_type(event_hash)
|
129
|
+
log_info("Sending envelope [#{item_type}] #{event_id} to Sentry")
|
98
130
|
|
99
|
-
envelope
|
100
|
-
|
101
|
-
{"type":"#{item_type}","content_type":"application/json"}
|
102
|
-
#{JSON.generate(event_hash)}
|
103
|
-
ENVELOPE
|
131
|
+
envelope.to_s
|
132
|
+
end
|
104
133
|
|
105
|
-
|
134
|
+
def record_lost_event(reason, item_type)
|
135
|
+
return unless @send_client_reports
|
136
|
+
return unless CLIENT_REPORT_REASONS.include?(reason)
|
106
137
|
|
107
|
-
|
138
|
+
item_type ||= 'event'
|
139
|
+
@discarded_events[[reason, item_type]] += 1
|
108
140
|
end
|
109
141
|
|
110
142
|
private
|
@@ -112,6 +144,32 @@ module Sentry
|
|
112
144
|
def get_item_type(event_hash)
|
113
145
|
event_hash[:type] || event_hash["type"] || "event"
|
114
146
|
end
|
147
|
+
|
148
|
+
def fetch_pending_client_report
|
149
|
+
return nil unless @send_client_reports
|
150
|
+
return nil if @last_client_report_sent > Time.now - CLIENT_REPORT_INTERVAL
|
151
|
+
return nil if @discarded_events.empty?
|
152
|
+
|
153
|
+
discarded_events_hash = @discarded_events.map do |key, val|
|
154
|
+
reason, type = key
|
155
|
+
|
156
|
+
# 'event' has to be mapped to 'error'
|
157
|
+
category = type == 'transaction' ? 'transaction' : 'error'
|
158
|
+
|
159
|
+
{ reason: reason, category: category, quantity: val }
|
160
|
+
end
|
161
|
+
|
162
|
+
item_header = { type: 'client_report' }
|
163
|
+
item_payload = {
|
164
|
+
timestamp: Sentry.utc_now.iso8601,
|
165
|
+
discarded_events: discarded_events_hash
|
166
|
+
}
|
167
|
+
|
168
|
+
@discarded_events = Hash.new(0)
|
169
|
+
@last_client_report_sent = Time.now
|
170
|
+
|
171
|
+
[item_header, item_payload]
|
172
|
+
end
|
115
173
|
end
|
116
174
|
end
|
117
175
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sentry
|
4
|
+
module CustomInspection
|
5
|
+
def inspect
|
6
|
+
attr_strings = (instance_variables - self.class::SKIP_INSPECTION_ATTRIBUTES).each_with_object([]) do |attr, result|
|
7
|
+
value = instance_variable_get(attr)
|
8
|
+
result << "#{attr}=#{value.inspect}" if value
|
9
|
+
end
|
10
|
+
|
11
|
+
"#<#{self.class.name} #{attr_strings.join(", ")}>"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,19 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Sentry
|
2
4
|
module Utils
|
3
5
|
module ExceptionCauseChain
|
4
6
|
def self.exception_to_array(exception)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
exceptions = [exception]
|
8
|
+
|
9
|
+
while exception.cause
|
10
|
+
exception = exception.cause
|
11
|
+
break if exceptions.any? { |e| e.object_id == exception.object_id }
|
10
12
|
|
11
|
-
|
12
|
-
end
|
13
|
-
exceptions
|
14
|
-
else
|
15
|
-
[exception]
|
13
|
+
exceptions << exception
|
16
14
|
end
|
15
|
+
|
16
|
+
exceptions
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
data/lib/sentry/utils/real_ip.rb
CHANGED
data/lib/sentry/version.rb
CHANGED
data/lib/sentry-ruby.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "English"
|
2
4
|
require "forwardable"
|
3
5
|
require "time"
|
@@ -37,6 +39,22 @@ module Sentry
|
|
37
39
|
THREAD_LOCAL = :sentry_hub
|
38
40
|
|
39
41
|
class << self
|
42
|
+
def exception_locals_tp
|
43
|
+
@exception_locals_tp ||= TracePoint.new(:raise) do |tp|
|
44
|
+
exception = tp.raised_exception
|
45
|
+
|
46
|
+
# don't collect locals again if the exception is re-raised
|
47
|
+
next if exception.instance_variable_get(:@sentry_locals)
|
48
|
+
next unless tp.binding
|
49
|
+
|
50
|
+
locals = tp.binding.local_variables.each_with_object({}) do |local, result|
|
51
|
+
result[local] = tp.binding.local_variable_get(local)
|
52
|
+
end
|
53
|
+
|
54
|
+
exception.instance_variable_set(:@sentry_locals, locals)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
40
58
|
attr_accessor :background_worker
|
41
59
|
|
42
60
|
##### Patch Registration #####
|
@@ -88,6 +106,14 @@ module Sentry
|
|
88
106
|
Thread.current.thread_variable_set(THREAD_LOCAL, hub)
|
89
107
|
@main_hub = hub
|
90
108
|
@background_worker = Sentry::BackgroundWorker.new(config)
|
109
|
+
|
110
|
+
if config.capture_exception_frame_locals
|
111
|
+
exception_locals_tp.enable
|
112
|
+
end
|
113
|
+
|
114
|
+
at_exit do
|
115
|
+
@background_worker.shutdown
|
116
|
+
end
|
91
117
|
end
|
92
118
|
|
93
119
|
# Returns an uri for security policy reporting that's generated from the given DSN
|
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: 4.
|
4
|
+
version: 4.8.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: 2021-
|
11
|
+
date: 2021-11-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- lib/sentry/core_ext/object/deep_dup.rb
|
69
69
|
- lib/sentry/core_ext/object/duplicable.rb
|
70
70
|
- lib/sentry/dsn.rb
|
71
|
+
- lib/sentry/envelope.rb
|
71
72
|
- lib/sentry/event.rb
|
72
73
|
- lib/sentry/exceptions.rb
|
73
74
|
- lib/sentry/hub.rb
|
@@ -85,6 +86,7 @@ files:
|
|
85
86
|
- lib/sentry/rack.rb
|
86
87
|
- lib/sentry/rack/capture_exceptions.rb
|
87
88
|
- lib/sentry/rake.rb
|
89
|
+
- lib/sentry/release_detector.rb
|
88
90
|
- lib/sentry/scope.rb
|
89
91
|
- lib/sentry/span.rb
|
90
92
|
- lib/sentry/transaction.rb
|
@@ -94,6 +96,7 @@ files:
|
|
94
96
|
- lib/sentry/transport/dummy_transport.rb
|
95
97
|
- lib/sentry/transport/http_transport.rb
|
96
98
|
- lib/sentry/utils/argument_checking_helper.rb
|
99
|
+
- lib/sentry/utils/custom_inspection.rb
|
97
100
|
- lib/sentry/utils/exception_cause_chain.rb
|
98
101
|
- lib/sentry/utils/logging_helper.rb
|
99
102
|
- lib/sentry/utils/real_ip.rb
|