sentry-ruby-core 4.8.0 → 4.9.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/Gemfile +2 -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 +33 -1
  11. data/lib/sentry/configuration.rb +88 -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 +26 -0
  16. data/lib/sentry/event.rb +54 -18
  17. data/lib/sentry/exceptions.rb +2 -0
  18. data/lib/sentry/hub.rb +2 -0
  19. data/lib/sentry/integrable.rb +2 -0
  20. data/lib/sentry/interface.rb +3 -10
  21. data/lib/sentry/interfaces/exception.rb +13 -3
  22. data/lib/sentry/interfaces/request.rb +34 -18
  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 +52 -64
  29. data/lib/sentry/rack/capture_exceptions.rb +2 -0
  30. data/lib/sentry/rack.rb +2 -0
  31. data/lib/sentry/rake.rb +16 -6
  32. data/lib/sentry/release_detector.rb +3 -0
  33. data/lib/sentry/scope.rb +75 -5
  34. data/lib/sentry/span.rb +84 -8
  35. data/lib/sentry/transaction.rb +44 -9
  36. data/lib/sentry/transaction_event.rb +8 -0
  37. data/lib/sentry/transport/configuration.rb +2 -0
  38. data/lib/sentry/transport/dummy_transport.rb +2 -0
  39. data/lib/sentry/transport/http_transport.rb +6 -4
  40. data/lib/sentry/transport.rb +23 -25
  41. data/lib/sentry/utils/argument_checking_helper.rb +2 -0
  42. data/lib/sentry/utils/custom_inspection.rb +2 -0
  43. data/lib/sentry/utils/exception_cause_chain.rb +2 -0
  44. data/lib/sentry/utils/logging_helper.rb +6 -4
  45. data/lib/sentry/utils/real_ip.rb +2 -0
  46. data/lib/sentry/utils/request_id.rb +2 -0
  47. data/lib/sentry/version.rb +3 -1
  48. data/lib/sentry-ruby.rb +122 -29
  49. data/sentry-ruby.gemspec +1 -1
  50. metadata +4 -2
@@ -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
@@ -103,31 +109,29 @@ module Sentry
103
109
  def encode(event)
104
110
  # Convert to hash
105
111
  event_payload = event.to_hash
106
-
107
112
  event_id = event_payload[:event_id] || event_payload["event_id"]
108
113
  item_type = get_item_type(event_payload)
109
114
 
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
- }
115
+ envelope = Envelope.new(
116
+ {
117
+ event_id: event_id,
118
+ dsn: @dsn.to_s,
119
+ sdk: Sentry.sdk_meta,
120
+ sent_at: Sentry.utc_now.iso8601
121
+ }
122
+ )
116
123
 
117
- event_header = { type: item_type, content_type: 'application/json' }
124
+ envelope.add_item(
125
+ { type: item_type, content_type: 'application/json' },
126
+ event_payload
127
+ )
118
128
 
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
129
+ client_report_headers, client_report_payload = fetch_pending_client_report
130
+ envelope.add_item(client_report_headers, client_report_payload) if client_report_headers
127
131
 
128
132
  log_info("Sending envelope [#{item_type}] #{event_id} to Sentry")
129
133
 
130
- envelope
134
+ envelope.to_s
131
135
  end
132
136
 
133
137
  def record_lost_event(reason, item_type)
@@ -159,21 +163,15 @@ module Sentry
159
163
  end
160
164
 
161
165
  item_header = { type: 'client_report' }
162
-
163
166
  item_payload = {
164
167
  timestamp: Sentry.utc_now.iso8601,
165
168
  discarded_events: discarded_events_hash
166
169
  }
167
170
 
168
- client_report_item = <<~CLIENT_REPORT_ITEM
169
- #{JSON.generate(item_header)}
170
- #{JSON.generate(item_payload)}
171
- CLIENT_REPORT_ITEM
172
-
173
171
  @discarded_events = Hash.new(0)
174
172
  @last_client_report_sent = Time.now
175
173
 
176
- client_report_item
174
+ [item_header, item_payload]
177
175
  end
178
176
  end
179
177
  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 = "4.9.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"
@@ -16,7 +18,6 @@ require "sentry/transaction"
16
18
  require "sentry/hub"
17
19
  require "sentry/background_worker"
18
20
 
19
-
20
21
  [
21
22
  "sentry/rake",
22
23
  "sentry/rack",
@@ -37,6 +38,7 @@ module Sentry
37
38
  THREAD_LOCAL = :sentry_hub
38
39
 
39
40
  class << self
41
+ # @!visibility private
40
42
  def exception_locals_tp
41
43
  @exception_locals_tp ||= TracePoint.new(:raise) do |tp|
42
44
  exception = tp.raised_exception
@@ -53,46 +55,100 @@ module Sentry
53
55
  end
54
56
  end
55
57
 
58
+ # @!attribute [rw] background_worker
59
+ # @return [BackgroundWorker]
56
60
  attr_accessor :background_worker
57
61
 
58
62
  ##### Patch Registration #####
59
- #
63
+
64
+ # @!visibility private
60
65
  def register_patch(&block)
61
66
  registered_patches << block
62
67
  end
63
68
 
69
+ # @!visibility private
64
70
  def apply_patches(config)
65
71
  registered_patches.each do |patch|
66
72
  patch.call(config)
67
73
  end
68
74
  end
69
75
 
76
+ # @!visibility private
70
77
  def registered_patches
71
78
  @registered_patches ||= []
72
79
  end
73
80
 
74
81
  ##### Integrations #####
75
- #
82
+
76
83
  # Returns a hash that contains all the integrations that have been registered to the main SDK.
84
+ #
85
+ # @return [Hash{String=>Hash}]
77
86
  def integrations
78
87
  @integrations ||= {}
79
88
  end
80
89
 
81
90
  # Registers the SDK integration with its name and version.
91
+ #
92
+ # @param name [String] name of the integration
93
+ # @param version [String] version of the integration
82
94
  def register_integration(name, version)
83
95
  meta = { name: "sentry.ruby.#{name}", version: version }.freeze
84
96
  integrations[name.to_s] = meta
85
97
  end
86
98
 
87
99
  ##### Method Delegation #####
88
- #
100
+
89
101
  extend Forwardable
90
102
 
103
+ # @!macro [new] configuration
104
+ # The Configuration object that's used for configuring the client and its transport.
105
+ # @return [Configuration]
106
+ # @!macro [new] send_event
107
+ # Sends the event to Sentry.
108
+ # @param event [Event] the event to be sent.
109
+ # @param hint [Hash] the hint data that'll be passed to `before_send` callback.
110
+ # @return [Event]
111
+
112
+ # @!method configuration
113
+ # @!macro configuration
114
+ # @!method send_event
115
+ # @!macro send_event
91
116
  def_delegators :get_current_client, :configuration, :send_event
117
+
118
+ # @!macro [new] set_extras
119
+ # Updates the scope's extras attribute by merging with the old value.
120
+ # @param extras [Hash]
121
+ # @return [Hash]
122
+ # @!macro [new] set_user
123
+ # Sets the scope's user attribute.
124
+ # @param user [Hash]
125
+ # @return [Hash]
126
+ # @!macro [new] set_context
127
+ # Adds a new key-value pair to current contexts.
128
+ # @param key [String, Symbol]
129
+ # @param value [Object]
130
+ # @return [Hash]
131
+ # @!macro [new] set_tags
132
+ # Updates the scope's tags attribute by merging with the old value.
133
+ # @param tags [Hash]
134
+ # @return [Hash]
135
+
136
+ # @!method set_tags
137
+ # @!macro set_tags
138
+ # @!method set_extras
139
+ # @!macro set_extras
140
+ # @!method set_user
141
+ # @!macro set_user
142
+ # @!method set_context
143
+ # @!macro set_context
92
144
  def_delegators :get_current_scope, :set_tags, :set_extras, :set_user, :set_context
93
145
 
94
146
  ##### Main APIs #####
147
+
148
+ # Initializes the SDK with given configuration.
95
149
  #
150
+ # @yieldparam config [Configuration]
151
+ # @return [void]
96
152
  def init(&block)
97
153
  config = Configuration.new
98
154
  yield(config) if block_given?
@@ -108,26 +164,42 @@ module Sentry
108
164
  if config.capture_exception_frame_locals
109
165
  exception_locals_tp.enable
110
166
  end
167
+
168
+ at_exit do
169
+ @background_worker.shutdown
170
+ end
171
+ end
172
+
173
+ # Returns true if the SDK is initialized.
174
+ #
175
+ # @return [Boolean]
176
+ def initialized?
177
+ !!@main_hub
111
178
  end
112
179
 
113
180
  # Returns an uri for security policy reporting that's generated from the given DSN
114
181
  # (To learn more about security policy reporting: https://docs.sentry.io/product/security-policy-reporting/)
115
182
  #
116
183
  # It returns nil if
184
+ # - The SDK is not initialized yet.
185
+ # - The DSN is not provided or is invalid.
117
186
  #
118
- # 1. The SDK is not initialized yet.
119
- # 2. The DSN is not provided or is invalid.
187
+ # @return [String, nil]
120
188
  def csp_report_uri
121
189
  return unless initialized?
122
190
  configuration.csp_report_uri
123
191
  end
124
192
 
125
193
  # Returns the main thread's active hub.
194
+ #
195
+ # @return [Hub]
126
196
  def get_main_hub
127
197
  @main_hub
128
198
  end
129
199
 
130
200
  # Takes an instance of Sentry::Breadcrumb and stores it to the current active scope.
201
+ #
202
+ # @return [Breadcrumb, nil]
131
203
  def add_breadcrumb(breadcrumb, **options)
132
204
  get_current_hub&.add_breadcrumb(breadcrumb, **options)
133
205
  end
@@ -135,6 +207,8 @@ module Sentry
135
207
  # Returns the current active hub.
136
208
  # If the current thread doesn't have an active hub, it will clone the main thread's active hub,
137
209
  # stores it in the current thread, and then returns it.
210
+ #
211
+ # @return [Hub]
138
212
  def get_current_hub
139
213
  # we need to assign a hub to the current thread if it doesn't have one yet
140
214
  #
@@ -145,85 +219,105 @@ module Sentry
145
219
  end
146
220
 
147
221
  # Returns the current active client.
222
+ # @return [Client, nil]
148
223
  def get_current_client
149
224
  get_current_hub&.current_client
150
225
  end
151
226
 
152
227
  # Returns the current active scope.
228
+ #
229
+ # @return [Scope, nil]
153
230
  def get_current_scope
154
231
  get_current_hub&.current_scope
155
232
  end
156
233
 
157
234
  # Clones the main thread's active hub and stores it to the current thread.
235
+ #
236
+ # @return [void]
158
237
  def clone_hub_to_current_thread
159
238
  Thread.current.thread_variable_set(THREAD_LOCAL, get_main_hub.clone)
160
239
  end
161
240
 
162
241
  # Takes a block and yields the current active scope.
163
242
  #
164
- # ```ruby
165
- # Sentry.configure_scope do |scope|
166
- # scope.set_tags(foo: "bar")
167
- # end
243
+ # @example
244
+ # Sentry.configure_scope do |scope|
245
+ # scope.set_tags(foo: "bar")
246
+ # end
168
247
  #
169
- # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
170
- # ```
248
+ # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
171
249
  #
250
+ # @yieldparam scope [Scope]
251
+ # @return [void]
172
252
  def configure_scope(&block)
173
253
  get_current_hub&.configure_scope(&block)
174
254
  end
175
255
 
176
256
  # Takes a block and yields a temporary scope.
177
257
  # 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:
258
+ # scope inside the block.
179
259
  #
180
- # ```ruby
181
- # Sentry.configure_scope do |scope|
182
- # scope.set_tags(foo: "bar")
183
- # end
260
+ # @example
261
+ # Sentry.configure_scope do |scope|
262
+ # scope.set_tags(foo: "bar")
263
+ # end
184
264
  #
185
- # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
265
+ # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
186
266
  #
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
267
+ # Sentry.with_scope do |temp_scope|
268
+ # temp_scope.set_tags(foo: "baz")
269
+ # Sentry.capture_message("test message 2") # this event will have tags { foo: "baz" }
270
+ # end
191
271
  #
192
- # Sentry.capture_message("test message 3") # this event will have tags { foo: "bar" }
193
- # ```
272
+ # Sentry.capture_message("test message 3") # this event will have tags { foo: "bar" }
194
273
  #
274
+ # @yieldparam scope [Scope]
275
+ # @return [void]
195
276
  def with_scope(&block)
196
277
  get_current_hub&.with_scope(&block)
197
278
  end
198
279
 
199
280
  # Takes an exception and reports it to Sentry via the currently active hub.
281
+ #
282
+ # @yieldparam scope [Scope]
283
+ # @return [Event, nil]
200
284
  def capture_exception(exception, **options, &block)
201
285
  get_current_hub&.capture_exception(exception, **options, &block)
202
286
  end
203
287
 
204
288
  # Takes a message string and reports it to Sentry via the currently active hub.
289
+ #
290
+ # @yieldparam scope [Scope]
291
+ # @return [Event, nil]
205
292
  def capture_message(message, **options, &block)
206
293
  get_current_hub&.capture_message(message, **options, &block)
207
294
  end
208
295
 
209
296
  # Takes an instance of Sentry::Event and dispatches it to the currently active hub.
297
+ #
298
+ # @return [Event, nil]
210
299
  def capture_event(event)
211
300
  get_current_hub&.capture_event(event)
212
301
  end
213
302
 
214
303
  # Takes or initializes a new Sentry::Transaction and makes a sampling decision for it.
304
+ #
305
+ # @return [Transaction, nil]
215
306
  def start_transaction(**options)
216
307
  get_current_hub&.start_transaction(**options)
217
308
  end
218
309
 
219
310
  # Returns the id of the lastly reported Sentry::Event.
311
+ #
312
+ # @return [String, nil]
220
313
  def last_event_id
221
314
  get_current_hub&.last_event_id
222
315
  end
223
316
 
224
317
 
225
318
  ##### Helpers #####
226
- #
319
+
320
+ # @!visibility private
227
321
  def sys_command(command)
228
322
  result = `#{command} 2>&1` rescue nil
229
323
  return if result.nil? || result.empty? || ($CHILD_STATUS && $CHILD_STATUS.exitstatus != 0)
@@ -231,18 +325,17 @@ module Sentry
231
325
  result.strip
232
326
  end
233
327
 
234
- def initialized?
235
- !!@main_hub
236
- end
237
-
328
+ # @!visibility private
238
329
  def logger
239
330
  configuration.logger
240
331
  end
241
332
 
333
+ # @!visibility private
242
334
  def sdk_meta
243
335
  META
244
336
  end
245
337
 
338
+ # @!visibility private
246
339
  def utc_now
247
340
  Time.now.utc
248
341
  end
data/sentry-ruby.gemspec CHANGED
@@ -18,6 +18,6 @@ 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"
21
+ spec.add_dependency "faraday", "~> 1.0"
22
22
  spec.add_dependency "concurrent-ruby", '~> 1.0', '>= 1.0.2'
23
23
  end
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.8.0
4
+ version: 4.9.0
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-11 00:00:00.000000000 Z
11
+ date: 2022-01-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -48,6 +48,7 @@ extra_rdoc_files:
48
48
  files:
49
49
  - ".gitignore"
50
50
  - ".rspec"
51
+ - ".yardopts"
51
52
  - CHANGELOG.md
52
53
  - CODE_OF_CONDUCT.md
53
54
  - Gemfile
@@ -68,6 +69,7 @@ files:
68
69
  - lib/sentry/core_ext/object/deep_dup.rb
69
70
  - lib/sentry/core_ext/object/duplicable.rb
70
71
  - lib/sentry/dsn.rb
72
+ - lib/sentry/envelope.rb
71
73
  - lib/sentry/event.rb
72
74
  - lib/sentry/exceptions.rb
73
75
  - lib/sentry/hub.rb