sentry-ruby-core 4.8.0 → 5.2.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.
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