sentry-ruby-core 4.8.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/Gemfile +3 -0
  4. data/README.md +2 -0
  5. data/lib/sentry/background_worker.rb +33 -3
  6. data/lib/sentry/backtrace.rb +1 -3
  7. data/lib/sentry/breadcrumb/sentry_logger.rb +2 -0
  8. data/lib/sentry/breadcrumb.rb +24 -3
  9. data/lib/sentry/breadcrumb_buffer.rb +16 -0
  10. data/lib/sentry/client.rb +38 -2
  11. data/lib/sentry/configuration.rb +94 -41
  12. data/lib/sentry/core_ext/object/deep_dup.rb +2 -0
  13. data/lib/sentry/core_ext/object/duplicable.rb +1 -0
  14. data/lib/sentry/dsn.rb +2 -0
  15. data/lib/sentry/envelope.rb +45 -0
  16. data/lib/sentry/event.rb +55 -18
  17. data/lib/sentry/exceptions.rb +2 -0
  18. data/lib/sentry/hub.rb +38 -2
  19. data/lib/sentry/integrable.rb +2 -0
  20. data/lib/sentry/interface.rb +3 -10
  21. data/lib/sentry/interfaces/exception.rb +14 -3
  22. data/lib/sentry/interfaces/request.rb +37 -20
  23. data/lib/sentry/interfaces/single_exception.rb +2 -0
  24. data/lib/sentry/interfaces/stacktrace.rb +6 -0
  25. data/lib/sentry/interfaces/stacktrace_builder.rb +39 -10
  26. data/lib/sentry/interfaces/threads.rb +12 -2
  27. data/lib/sentry/linecache.rb +3 -0
  28. data/lib/sentry/net/http.rb +54 -65
  29. data/lib/sentry/rack/capture_exceptions.rb +28 -24
  30. data/lib/sentry/rack.rb +2 -0
  31. data/lib/sentry/rake.rb +16 -6
  32. data/lib/sentry/redis.rb +90 -0
  33. data/lib/sentry/release_detector.rb +3 -0
  34. data/lib/sentry/scope.rb +85 -6
  35. data/lib/sentry/session.rb +35 -0
  36. data/lib/sentry/session_flusher.rb +79 -0
  37. data/lib/sentry/span.rb +84 -8
  38. data/lib/sentry/transaction.rb +48 -14
  39. data/lib/sentry/transaction_event.rb +8 -0
  40. data/lib/sentry/transport/configuration.rb +3 -2
  41. data/lib/sentry/transport/dummy_transport.rb +8 -1
  42. data/lib/sentry/transport/http_transport.rb +55 -42
  43. data/lib/sentry/transport.rb +79 -37
  44. data/lib/sentry/utils/argument_checking_helper.rb +2 -0
  45. data/lib/sentry/utils/custom_inspection.rb +2 -0
  46. data/lib/sentry/utils/exception_cause_chain.rb +2 -0
  47. data/lib/sentry/utils/logging_helper.rb +6 -4
  48. data/lib/sentry/utils/real_ip.rb +2 -0
  49. data/lib/sentry/utils/request_id.rb +2 -0
  50. data/lib/sentry/version.rb +3 -1
  51. data/lib/sentry-ruby.rb +212 -41
  52. data/sentry-ruby-core.gemspec +0 -1
  53. data/sentry-ruby.gemspec +0 -1
  54. metadata +7 -16
@@ -1,5 +1,8 @@
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
@@ -20,7 +23,10 @@ module Sentry
20
23
 
21
24
  include LoggingHelper
22
25
 
23
- attr_reader :logger, :rate_limits, :discarded_events, :last_client_report_sent
26
+ attr_reader :rate_limits, :discarded_events, :last_client_report_sent
27
+
28
+ # @deprecated Use Sentry.logger to retrieve the current logger instead.
29
+ attr_reader :logger
24
30
 
25
31
  def initialize(configuration)
26
32
  @logger = configuration.logger
@@ -40,23 +46,54 @@ module Sentry
40
46
  end
41
47
 
42
48
  def send_event(event)
43
- event_hash = event.to_hash
44
- item_type = get_item_type(event_hash)
49
+ envelope = envelope_from_event(event)
50
+ send_envelope(envelope)
51
+
52
+ event
53
+ end
54
+
55
+ def send_envelope(envelope)
56
+ reject_rate_limited_items(envelope)
45
57
 
46
- if is_rate_limited?(item_type)
47
- log_info("Envelope [#{item_type}] not sent: rate limiting")
48
- record_lost_event(:ratelimit_backoff, item_type)
58
+ return if envelope.items.empty?
49
59
 
50
- return
60
+ data, serialized_items = serialize_envelope(envelope)
61
+
62
+ if data
63
+ log_info("[Transport] Sending envelope with items [#{serialized_items.map(&:type).join(', ')}] #{envelope.event_id} to Sentry")
64
+ send_data(data)
51
65
  end
66
+ end
52
67
 
53
- encoded_data = encode(event)
68
+ def serialize_envelope(envelope)
69
+ serialized_items = []
70
+ serialized_results = []
54
71
 
55
- return nil unless encoded_data
72
+ envelope.items.each do |item|
73
+ result = item.to_s
56
74
 
57
- send_data(encoded_data)
75
+ if result.bytesize > Event::MAX_SERIALIZED_PAYLOAD_SIZE
76
+ item.payload.delete(:breadcrumbs)
77
+ result = item.to_s
78
+ end
58
79
 
59
- event
80
+ if result.bytesize > Event::MAX_SERIALIZED_PAYLOAD_SIZE
81
+ size_breakdown = item.payload.map do |key, value|
82
+ "#{key}: #{JSON.generate(value).bytesize}"
83
+ end.join(", ")
84
+
85
+ log_debug("Envelope item [#{item.type}] is still oversized without breadcrumbs: {#{size_breakdown}}")
86
+
87
+ next
88
+ end
89
+
90
+ serialized_results << result
91
+ serialized_items << item
92
+ end
93
+
94
+ data = [JSON.generate(envelope.headers), *serialized_results].join("\n") unless serialized_results.empty?
95
+
96
+ [data, serialized_items]
60
97
  end
61
98
 
62
99
  def is_rate_limited?(item_type)
@@ -65,6 +102,8 @@ module Sentry
65
102
  case item_type
66
103
  when "transaction"
67
104
  @rate_limits["transaction"]
105
+ when "sessions"
106
+ @rate_limits["session"]
68
107
  else
69
108
  @rate_limits["error"]
70
109
  end
@@ -100,32 +139,28 @@ module Sentry
100
139
  'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
101
140
  end
102
141
 
103
- def encode(event)
142
+ def envelope_from_event(event)
104
143
  # Convert to hash
105
144
  event_payload = event.to_hash
106
-
107
145
  event_id = event_payload[:event_id] || event_payload["event_id"]
108
146
  item_type = get_item_type(event_payload)
109
147
 
110
- envelope_header = {
111
- event_id: event_id,
112
- dsn: @dsn.to_s,
113
- sdk: Sentry.sdk_meta,
114
- sent_at: Sentry.utc_now.iso8601
115
- }
148
+ envelope = Envelope.new(
149
+ {
150
+ event_id: event_id,
151
+ dsn: @dsn.to_s,
152
+ sdk: Sentry.sdk_meta,
153
+ sent_at: Sentry.utc_now.iso8601
154
+ }
155
+ )
116
156
 
117
- event_header = { type: item_type, content_type: 'application/json' }
157
+ envelope.add_item(
158
+ { type: item_type, content_type: 'application/json' },
159
+ event_payload
160
+ )
118
161
 
119
- envelope = <<~ENVELOPE
120
- #{JSON.generate(envelope_header)}
121
- #{JSON.generate(event_header)}
122
- #{JSON.generate(event_payload)}
123
- ENVELOPE
124
-
125
- client_report = fetch_pending_client_report
126
- envelope << client_report if client_report
127
-
128
- log_info("Sending envelope [#{item_type}] #{event_id} to Sentry")
162
+ client_report_headers, client_report_payload = fetch_pending_client_report
163
+ envelope.add_item(client_report_headers, client_report_payload) if client_report_headers
129
164
 
130
165
  envelope
131
166
  end
@@ -159,21 +194,28 @@ module Sentry
159
194
  end
160
195
 
161
196
  item_header = { type: 'client_report' }
162
-
163
197
  item_payload = {
164
198
  timestamp: Sentry.utc_now.iso8601,
165
199
  discarded_events: discarded_events_hash
166
200
  }
167
201
 
168
- client_report_item = <<~CLIENT_REPORT_ITEM
169
- #{JSON.generate(item_header)}
170
- #{JSON.generate(item_payload)}
171
- CLIENT_REPORT_ITEM
172
-
173
202
  @discarded_events = Hash.new(0)
174
203
  @last_client_report_sent = Time.now
175
204
 
176
- client_report_item
205
+ [item_header, item_payload]
206
+ end
207
+
208
+ def reject_rate_limited_items(envelope)
209
+ envelope.items.reject! do |item|
210
+ if is_rate_limited?(item.type)
211
+ log_info("[Transport] Envelope item [#{item.type}] not sent: rate limiting")
212
+ record_lost_event(:ratelimit_backoff, item.type)
213
+
214
+ true
215
+ else
216
+ false
217
+ end
218
+ end
177
219
  end
178
220
  end
179
221
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  module ArgumentCheckingHelper
3
5
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  module CustomInspection
3
5
  def inspect
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  module Utils
3
5
  module ExceptionCauseChain
@@ -1,24 +1,26 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  module LoggingHelper
3
5
  def log_error(message, exception, debug: false)
4
6
  message = "#{message}: #{exception.message}"
5
7
  message += "\n#{exception.backtrace.join("\n")}" if debug
6
8
 
7
- logger.error(LOGGER_PROGNAME) do
9
+ @logger.error(LOGGER_PROGNAME) do
8
10
  message
9
11
  end
10
12
  end
11
13
 
12
14
  def log_info(message)
13
- logger.info(LOGGER_PROGNAME) { message }
15
+ @logger.info(LOGGER_PROGNAME) { message }
14
16
  end
15
17
 
16
18
  def log_debug(message)
17
- logger.debug(LOGGER_PROGNAME) { message }
19
+ @logger.debug(LOGGER_PROGNAME) { message }
18
20
  end
19
21
 
20
22
  def log_warn(message)
21
- logger.warn(LOGGER_PROGNAME) { message }
23
+ @logger.warn(LOGGER_PROGNAME) { message }
22
24
  end
23
25
  end
24
26
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ipaddr'
2
4
 
3
5
  # Based on ActionDispatch::RemoteIp. All security-related precautions from that
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  module Utils
3
5
  module RequestId
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
- VERSION = "4.8.0"
4
+ VERSION = "5.2.0"
3
5
  end
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"
@@ -15,7 +17,7 @@ require "sentry/span"
15
17
  require "sentry/transaction"
16
18
  require "sentry/hub"
17
19
  require "sentry/background_worker"
18
-
20
+ require "sentry/session_flusher"
19
21
 
20
22
  [
21
23
  "sentry/rake",
@@ -30,6 +32,8 @@ end
30
32
  module Sentry
31
33
  META = { "name" => "sentry.ruby", "version" => Sentry::VERSION }.freeze
32
34
 
35
+ CAPTURED_SIGNATURE = :@__sentry_captured
36
+
33
37
  LOGGER_PROGNAME = "sentry".freeze
34
38
 
35
39
  SENTRY_TRACE_HEADER_NAME = "sentry-trace".freeze
@@ -37,6 +41,7 @@ module Sentry
37
41
  THREAD_LOCAL = :sentry_hub
38
42
 
39
43
  class << self
44
+ # @!visibility private
40
45
  def exception_locals_tp
41
46
  @exception_locals_tp ||= TracePoint.new(:raise) do |tp|
42
47
  exception = tp.raised_exception
@@ -53,46 +58,130 @@ module Sentry
53
58
  end
54
59
  end
55
60
 
61
+ # @!attribute [rw] background_worker
62
+ # @return [BackgroundWorker]
56
63
  attr_accessor :background_worker
57
64
 
65
+ # @!attribute [r] session_flusher
66
+ # @return [SessionFlusher]
67
+ attr_reader :session_flusher
68
+
58
69
  ##### Patch Registration #####
59
- #
70
+
71
+ # @!visibility private
60
72
  def register_patch(&block)
61
73
  registered_patches << block
62
74
  end
63
75
 
76
+ # @!visibility private
64
77
  def apply_patches(config)
65
78
  registered_patches.each do |patch|
66
79
  patch.call(config)
67
80
  end
68
81
  end
69
82
 
83
+ # @!visibility private
70
84
  def registered_patches
71
85
  @registered_patches ||= []
72
86
  end
73
87
 
74
88
  ##### Integrations #####
75
- #
89
+
76
90
  # Returns a hash that contains all the integrations that have been registered to the main SDK.
91
+ #
92
+ # @return [Hash{String=>Hash}]
77
93
  def integrations
78
94
  @integrations ||= {}
79
95
  end
80
96
 
81
97
  # Registers the SDK integration with its name and version.
98
+ #
99
+ # @param name [String] name of the integration
100
+ # @param version [String] version of the integration
82
101
  def register_integration(name, version)
83
102
  meta = { name: "sentry.ruby.#{name}", version: version }.freeze
84
103
  integrations[name.to_s] = meta
85
104
  end
86
105
 
87
106
  ##### Method Delegation #####
88
- #
107
+
89
108
  extend Forwardable
90
109
 
91
- def_delegators :get_current_client, :configuration, :send_event
92
- def_delegators :get_current_scope, :set_tags, :set_extras, :set_user, :set_context
110
+ # @!macro [new] configuration
111
+ # The Configuration object that's used for configuring the client and its transport.
112
+ # @return [Configuration]
113
+ # @!macro [new] send_event
114
+ # Sends the event to Sentry.
115
+ # @param event [Event] the event to be sent.
116
+ # @param hint [Hash] the hint data that'll be passed to `before_send` callback.
117
+ # @return [Event]
118
+
119
+ # @!method configuration
120
+ # @!macro configuration
121
+ def configuration
122
+ return unless initialized?
123
+ get_current_client.configuration
124
+ end
125
+
126
+ # @!method send_event
127
+ # @!macro send_event
128
+ def send_event(*args)
129
+ return unless initialized?
130
+ get_current_client.send_event(*args)
131
+ end
132
+
133
+ # @!macro [new] set_extras
134
+ # Updates the scope's extras attribute by merging with the old value.
135
+ # @param extras [Hash]
136
+ # @return [Hash]
137
+ # @!macro [new] set_user
138
+ # Sets the scope's user attribute.
139
+ # @param user [Hash]
140
+ # @return [Hash]
141
+ # @!macro [new] set_context
142
+ # Adds a new key-value pair to current contexts.
143
+ # @param key [String, Symbol]
144
+ # @param value [Object]
145
+ # @return [Hash]
146
+ # @!macro [new] set_tags
147
+ # Updates the scope's tags attribute by merging with the old value.
148
+ # @param tags [Hash]
149
+ # @return [Hash]
150
+
151
+ # @!method set_tags
152
+ # @!macro set_tags
153
+ def set_tags(*args)
154
+ return unless initialized?
155
+ get_current_scope.set_tags(*args)
156
+ end
157
+
158
+ # @!method set_extras
159
+ # @!macro set_extras
160
+ def set_extras(*args)
161
+ return unless initialized?
162
+ get_current_scope.set_extras(*args)
163
+ end
164
+
165
+ # @!method set_user
166
+ # @!macro set_user
167
+ def set_user(*args)
168
+ return unless initialized?
169
+ get_current_scope.set_user(*args)
170
+ end
171
+
172
+ # @!method set_context
173
+ # @!macro set_context
174
+ def set_context(*args)
175
+ return unless initialized?
176
+ get_current_scope.set_context(*args)
177
+ end
93
178
 
94
179
  ##### Main APIs #####
180
+
181
+ # Initializes the SDK with given configuration.
95
182
  #
183
+ # @yieldparam config [Configuration]
184
+ # @return [void]
96
185
  def init(&block)
97
186
  config = Configuration.new
98
187
  yield(config) if block_given?
@@ -105,36 +194,62 @@ module Sentry
105
194
  @main_hub = hub
106
195
  @background_worker = Sentry::BackgroundWorker.new(config)
107
196
 
197
+ @session_flusher = if config.auto_session_tracking
198
+ Sentry::SessionFlusher.new(config, client)
199
+ else
200
+ nil
201
+ end
202
+
108
203
  if config.capture_exception_frame_locals
109
204
  exception_locals_tp.enable
110
205
  end
206
+
207
+ at_exit do
208
+ @session_flusher&.kill
209
+ @background_worker.shutdown
210
+ end
211
+ end
212
+
213
+ # Returns true if the SDK is initialized.
214
+ #
215
+ # @return [Boolean]
216
+ def initialized?
217
+ !!get_main_hub
111
218
  end
112
219
 
113
220
  # Returns an uri for security policy reporting that's generated from the given DSN
114
221
  # (To learn more about security policy reporting: https://docs.sentry.io/product/security-policy-reporting/)
115
222
  #
116
223
  # It returns nil if
224
+ # - The SDK is not initialized yet.
225
+ # - The DSN is not provided or is invalid.
117
226
  #
118
- # 1. The SDK is not initialized yet.
119
- # 2. The DSN is not provided or is invalid.
227
+ # @return [String, nil]
120
228
  def csp_report_uri
121
229
  return unless initialized?
122
230
  configuration.csp_report_uri
123
231
  end
124
232
 
125
233
  # Returns the main thread's active hub.
234
+ #
235
+ # @return [Hub]
126
236
  def get_main_hub
127
237
  @main_hub
128
238
  end
129
239
 
130
240
  # Takes an instance of Sentry::Breadcrumb and stores it to the current active scope.
241
+ #
242
+ # @return [Breadcrumb, nil]
131
243
  def add_breadcrumb(breadcrumb, **options)
132
- get_current_hub&.add_breadcrumb(breadcrumb, **options)
244
+ return unless initialized?
245
+ get_current_hub.add_breadcrumb(breadcrumb, **options)
133
246
  end
134
247
 
135
248
  # Returns the current active hub.
136
249
  # If the current thread doesn't have an active hub, it will clone the main thread's active hub,
137
250
  # stores it in the current thread, and then returns it.
251
+ #
252
+ # @return [Hub]
138
253
  def get_current_hub
139
254
  # we need to assign a hub to the current thread if it doesn't have one yet
140
255
  #
@@ -145,85 +260,141 @@ module Sentry
145
260
  end
146
261
 
147
262
  # Returns the current active client.
263
+ # @return [Client, nil]
148
264
  def get_current_client
149
- get_current_hub&.current_client
265
+ return unless initialized?
266
+ get_current_hub.current_client
150
267
  end
151
268
 
152
269
  # Returns the current active scope.
270
+ #
271
+ # @return [Scope, nil]
153
272
  def get_current_scope
154
- get_current_hub&.current_scope
273
+ return unless initialized?
274
+ get_current_hub.current_scope
155
275
  end
156
276
 
157
277
  # Clones the main thread's active hub and stores it to the current thread.
278
+ #
279
+ # @return [void]
158
280
  def clone_hub_to_current_thread
159
281
  Thread.current.thread_variable_set(THREAD_LOCAL, get_main_hub.clone)
160
282
  end
161
283
 
162
284
  # Takes a block and yields the current active scope.
163
285
  #
164
- # ```ruby
165
- # Sentry.configure_scope do |scope|
166
- # scope.set_tags(foo: "bar")
167
- # end
286
+ # @example
287
+ # Sentry.configure_scope do |scope|
288
+ # scope.set_tags(foo: "bar")
289
+ # end
168
290
  #
169
- # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
170
- # ```
291
+ # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
171
292
  #
293
+ # @yieldparam scope [Scope]
294
+ # @return [void]
172
295
  def configure_scope(&block)
173
- get_current_hub&.configure_scope(&block)
296
+ return unless initialized?
297
+ get_current_hub.configure_scope(&block)
174
298
  end
175
299
 
176
300
  # Takes a block and yields a temporary scope.
177
301
  # The temporary scope will inherit all the attributes from the current active scope and replace it to be the active
178
- # scope inside the block. For example:
302
+ # scope inside the block.
179
303
  #
180
- # ```ruby
181
- # Sentry.configure_scope do |scope|
182
- # scope.set_tags(foo: "bar")
183
- # end
304
+ # @example
305
+ # Sentry.configure_scope do |scope|
306
+ # scope.set_tags(foo: "bar")
307
+ # end
184
308
  #
185
- # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
309
+ # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
186
310
  #
187
- # Sentry.with_scope do |temp_scope|
188
- # temp_scope.set_tags(foo: "baz")
189
- # Sentry.capture_message("test message 2") # this event will have tags { foo: "baz" }
190
- # end
311
+ # Sentry.with_scope do |temp_scope|
312
+ # temp_scope.set_tags(foo: "baz")
313
+ # Sentry.capture_message("test message 2") # this event will have tags { foo: "baz" }
314
+ # end
191
315
  #
192
- # Sentry.capture_message("test message 3") # this event will have tags { foo: "bar" }
193
- # ```
316
+ # Sentry.capture_message("test message 3") # this event will have tags { foo: "bar" }
194
317
  #
318
+ # @yieldparam scope [Scope]
319
+ # @return [void]
195
320
  def with_scope(&block)
196
- get_current_hub&.with_scope(&block)
321
+ return unless initialized?
322
+ get_current_hub.with_scope(&block)
323
+ end
324
+
325
+ # Wrap a given block with session tracking.
326
+ # Aggregate sessions in minutely buckets will be recorded
327
+ # around this block and flushed every minute.
328
+ #
329
+ # @example
330
+ # Sentry.with_session_tracking do
331
+ # a = 1 + 1 # new session recorded with :exited status
332
+ # end
333
+ #
334
+ # Sentry.with_session_tracking do
335
+ # 1 / 0
336
+ # rescue => e
337
+ # Sentry.capture_exception(e) # new session recorded with :errored status
338
+ # end
339
+ # @return [void]
340
+ def with_session_tracking(&block)
341
+ return yield unless initialized?
342
+ get_current_hub.with_session_tracking(&block)
197
343
  end
198
344
 
199
345
  # Takes an exception and reports it to Sentry via the currently active hub.
346
+ #
347
+ # @yieldparam scope [Scope]
348
+ # @return [Event, nil]
200
349
  def capture_exception(exception, **options, &block)
201
- get_current_hub&.capture_exception(exception, **options, &block)
350
+ return unless initialized?
351
+ get_current_hub.capture_exception(exception, **options, &block)
202
352
  end
203
353
 
204
354
  # Takes a message string and reports it to Sentry via the currently active hub.
355
+ #
356
+ # @yieldparam scope [Scope]
357
+ # @return [Event, nil]
205
358
  def capture_message(message, **options, &block)
206
- get_current_hub&.capture_message(message, **options, &block)
359
+ return unless initialized?
360
+ get_current_hub.capture_message(message, **options, &block)
207
361
  end
208
362
 
209
363
  # Takes an instance of Sentry::Event and dispatches it to the currently active hub.
364
+ #
365
+ # @return [Event, nil]
210
366
  def capture_event(event)
211
- get_current_hub&.capture_event(event)
367
+ return unless initialized?
368
+ get_current_hub.capture_event(event)
212
369
  end
213
370
 
214
371
  # Takes or initializes a new Sentry::Transaction and makes a sampling decision for it.
372
+ #
373
+ # @return [Transaction, nil]
215
374
  def start_transaction(**options)
216
- get_current_hub&.start_transaction(**options)
375
+ return unless initialized?
376
+ get_current_hub.start_transaction(**options)
217
377
  end
218
378
 
219
379
  # Returns the id of the lastly reported Sentry::Event.
380
+ #
381
+ # @return [String, nil]
220
382
  def last_event_id
221
- get_current_hub&.last_event_id
383
+ return unless initialized?
384
+ get_current_hub.last_event_id
222
385
  end
223
386
 
387
+ # Checks if the exception object has been captured by the SDK.
388
+ #
389
+ # @return [Boolean]
390
+ def exception_captured?(exc)
391
+ return false unless initialized?
392
+ !!exc.instance_variable_get(CAPTURED_SIGNATURE)
393
+ end
224
394
 
225
395
  ##### Helpers #####
226
- #
396
+
397
+ # @!visibility private
227
398
  def sys_command(command)
228
399
  result = `#{command} 2>&1` rescue nil
229
400
  return if result.nil? || result.empty? || ($CHILD_STATUS && $CHILD_STATUS.exitstatus != 0)
@@ -231,18 +402,17 @@ module Sentry
231
402
  result.strip
232
403
  end
233
404
 
234
- def initialized?
235
- !!@main_hub
236
- end
237
-
405
+ # @!visibility private
238
406
  def logger
239
407
  configuration.logger
240
408
  end
241
409
 
410
+ # @!visibility private
242
411
  def sdk_meta
243
412
  META
244
413
  end
245
414
 
415
+ # @!visibility private
246
416
  def utc_now
247
417
  Time.now.utc
248
418
  end
@@ -251,3 +421,4 @@ end
251
421
 
252
422
  # patches
253
423
  require "sentry/net/http"
424
+ require "sentry/redis"
@@ -22,6 +22,5 @@ Gem::Specification.new do |spec|
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ["lib"]
24
24
 
25
- spec.add_dependency "faraday"
26
25
  spec.add_dependency "concurrent-ruby"
27
26
  end
data/sentry-ruby.gemspec CHANGED
@@ -18,6 +18,5 @@ Gem::Specification.new do |spec|
18
18
  spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/master/CHANGELOG.md"
19
19
 
20
20
  spec.add_dependency "sentry-ruby-core", Sentry::VERSION
21
- spec.add_dependency "faraday", ">= 1.0"
22
21
  spec.add_dependency "concurrent-ruby", '~> 1.0', '>= 1.0.2'
23
22
  end