sentry-ruby-core 4.8.0 → 4.8.2

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/Gemfile +2 -0
  4. data/lib/sentry/background_worker.rb +30 -2
  5. data/lib/sentry/backtrace.rb +1 -0
  6. data/lib/sentry/breadcrumb/sentry_logger.rb +2 -0
  7. data/lib/sentry/breadcrumb.rb +2 -0
  8. data/lib/sentry/breadcrumb_buffer.rb +2 -0
  9. data/lib/sentry/client.rb +2 -0
  10. data/lib/sentry/configuration.rb +85 -39
  11. data/lib/sentry/core_ext/object/deep_dup.rb +2 -0
  12. data/lib/sentry/core_ext/object/duplicable.rb +1 -0
  13. data/lib/sentry/dsn.rb +2 -0
  14. data/lib/sentry/envelope.rb +26 -0
  15. data/lib/sentry/exceptions.rb +2 -0
  16. data/lib/sentry/hub.rb +2 -0
  17. data/lib/sentry/integrable.rb +2 -0
  18. data/lib/sentry/interface.rb +2 -0
  19. data/lib/sentry/interfaces/exception.rb +2 -0
  20. data/lib/sentry/interfaces/single_exception.rb +2 -0
  21. data/lib/sentry/interfaces/stacktrace.rb +2 -0
  22. data/lib/sentry/interfaces/stacktrace_builder.rb +2 -0
  23. data/lib/sentry/interfaces/threads.rb +2 -0
  24. data/lib/sentry/linecache.rb +3 -0
  25. data/lib/sentry/net/http.rb +3 -0
  26. data/lib/sentry/rack/capture_exceptions.rb +2 -0
  27. data/lib/sentry/rack.rb +2 -0
  28. data/lib/sentry/rake.rb +16 -6
  29. data/lib/sentry/release_detector.rb +3 -0
  30. data/lib/sentry/scope.rb +8 -4
  31. data/lib/sentry/span.rb +1 -0
  32. data/lib/sentry/transaction.rb +2 -0
  33. data/lib/sentry/transport/configuration.rb +2 -0
  34. data/lib/sentry/transport/dummy_transport.rb +2 -0
  35. data/lib/sentry/transport/http_transport.rb +6 -4
  36. data/lib/sentry/transport.rb +19 -24
  37. data/lib/sentry/utils/argument_checking_helper.rb +2 -0
  38. data/lib/sentry/utils/custom_inspection.rb +2 -0
  39. data/lib/sentry/utils/exception_cause_chain.rb +2 -0
  40. data/lib/sentry/utils/logging_helper.rb +2 -0
  41. data/lib/sentry/utils/real_ip.rb +2 -0
  42. data/lib/sentry/utils/request_id.rb +2 -0
  43. data/lib/sentry/version.rb +3 -1
  44. data/lib/sentry-ruby.rb +82 -28
  45. data/sentry-ruby.gemspec +1 -1
  46. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f675111daf93ba05db7de62dcfa1dd9268f6ba009265de08e0e4f118ffea0c62
4
- data.tar.gz: 2ece2ccaf14be6cc5fa762b77a57cd63dcc3fe52a03987c8c4136a43ec62bbd1
3
+ metadata.gz: '09a04a594b731f8d13770650138f1abd5bce410dad2f4cb4da1a2caa5ef7eba2'
4
+ data.tar.gz: e87cac23635525aa1b53772e262706a10948b52b634fafeedaf241c8b6d90c9a
5
5
  SHA512:
6
- metadata.gz: d5d9405c41879a40ba0c0205fa08e38fa5b3ed243276181239be63f0baa0b739b37ac91ecb86abd76768c4c5a706f1f7b7e47d7eadd357f2116ec2ec9bd913d5
7
- data.tar.gz: abb46869f2eba00f053096e5568829815b02520db31fe9c98bbfabea40b5dcbe6d438ca97287ca7f9b4fee9a4710b49dec73b9196a3650d3a811184a960a09a7
6
+ metadata.gz: db6311ce62c548e835cbc49c7616ac244d853c3206599e1b540035b16da97bf05cd52a81602cf30215f15ee3e675d6857cdba628f87fc631e73d63d9523081d5
7
+ data.tar.gz: ae31de8f2bab17f15f16c8e6fea3fbbc359efc39c5f2ec5afba9fbfccbd4e77c22f051cd2b94278ff9c3ce92289448cccf1af8fc5df5da1fd7f25bb81458ae29
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ --exclude lib/sentry/utils/
2
+ --exclude lib/sentry/core_ext
data/Gemfile CHANGED
@@ -22,3 +22,5 @@ gem "benchmark-ips"
22
22
  gem "benchmark_driver"
23
23
  gem "benchmark-ipsa"
24
24
  gem "benchmark-memory"
25
+
26
+ gem "yard", "~> 0.9.27"
@@ -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
- block.call
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
@@ -4,6 +4,7 @@
4
4
 
5
5
  module Sentry
6
6
  # Front end to parsing the backtrace for each notice
7
+ # @api private
7
8
  class Backtrace
8
9
  # Handles backtrace parsing line by line
9
10
  class Line
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'logger'
2
4
 
3
5
  module Sentry
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class Breadcrumb
3
5
  DATA_SERIALIZATION_ERROR_MESSAGE = "[data were removed due to serialization issues]"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "sentry/breadcrumb"
2
4
 
3
5
  module Sentry
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "concurrent/utility/processor_counter"
2
4
 
3
5
  require "sentry/utils/exception_cause_chain"
@@ -15,10 +17,15 @@ module Sentry
15
17
  # Directories to be recognized as part of your app. e.g. if you
16
18
  # have an `engines` dir at the root of your project, you may want
17
19
  # to set this to something like /(app|config|engines|lib)/
20
+ #
21
+ # @return [Regexp, nil]
18
22
  attr_accessor :app_dirs_pattern
19
23
 
20
24
  # Provide an object that responds to `call` to send events asynchronously.
21
25
  # E.g.: lambda { |event| Thread.new { Sentry.send_event(event) } }
26
+ #
27
+ # @deprecated It will be removed in the next major release. Please read https://github.com/getsentry/sentry-ruby/issues/1522 for more information
28
+ # @return [Proc, nil]
22
29
  attr_reader :async
23
30
 
24
31
  # to send events in a non-blocking way, sentry-ruby has its own background worker
@@ -28,74 +35,94 @@ module Sentry
28
35
  #
29
36
  # if you want to send events synchronously, set the value to 0
30
37
  # E.g.: config.background_worker_threads = 0
38
+ # @return [Integer]
31
39
  attr_accessor :background_worker_threads
32
40
 
33
41
  # a proc/lambda that takes an array of stack traces
34
42
  # it'll be used to silence (reduce) backtrace of the exception
35
43
  #
36
- # for example:
37
- #
38
- # ```ruby
39
- # Sentry.configuration.backtrace_cleanup_callback = lambda do |backtrace|
40
- # Rails.backtrace_cleaner.clean(backtrace)
41
- # end
42
- # ```
44
+ # @example
45
+ # config.backtrace_cleanup_callback = lambda do |backtrace|
46
+ # Rails.backtrace_cleaner.clean(backtrace)
47
+ # end
43
48
  #
49
+ # @return [Proc]
44
50
  attr_accessor :backtrace_cleanup_callback
45
51
 
46
52
  # Optional Proc, called before adding the breadcrumb to the current scope
47
- # E.g.: lambda { |breadcrumb, hint| breadcrumb }
48
- # E.g.: lambda { |breadcrumb, hint| nil }
49
- # E.g.: lambda { |breadcrumb, hint|
50
- # breadcrumb.message = 'a'
51
- # breadcrumb
52
- # }
53
+ # @example
54
+ # config.before = lambda do |breadcrumb, hint|
55
+ # breadcrumb.message = 'a'
56
+ # breadcrumb
57
+ # end
58
+ # @return [Proc]
53
59
  attr_reader :before_breadcrumb
54
60
 
55
- # Optional Proc, called before sending an event to the server/
56
- # E.g.: lambda { |event, hint| event }
57
- # E.g.: lambda { |event, hint| nil }
58
- # E.g.: lambda { |event, hint|
59
- # event[:message] = 'a'
60
- # event
61
- # }
61
+ # Optional Proc, called before sending an event to the server
62
+ # @example
63
+ # config.before_send = lambda do |event, hint|
64
+ # # skip ZeroDivisionError exceptions
65
+ # # note: hint[:exception] would be a String if you use async callback
66
+ # if hint[:exception].is_a?(ZeroDivisionError)
67
+ # nil
68
+ # else
69
+ # event
70
+ # end
71
+ # end
72
+ # @return [Proc]
62
73
  attr_reader :before_send
63
74
 
64
75
  # An array of breadcrumbs loggers to be used. Available options are:
65
76
  # - :sentry_logger
77
+ # - :http_logger
78
+ #
79
+ # And if you also use sentry-rails:
66
80
  # - :active_support_logger
81
+ # - :monotonic_active_support_logger
82
+ #
83
+ # @return [Array<Symbol>]
67
84
  attr_reader :breadcrumbs_logger
68
85
 
69
86
  # Whether to capture local variables from the raised exception's frame. Default is false.
87
+ # @return [Boolean]
70
88
  attr_accessor :capture_exception_frame_locals
71
89
 
72
90
  # Max number of breadcrumbs a breadcrumb buffer can hold
91
+ # @return [Integer]
73
92
  attr_accessor :max_breadcrumbs
74
93
 
75
94
  # Number of lines of code context to capture, or nil for none
95
+ # @return [Integer, nil]
76
96
  attr_accessor :context_lines
77
97
 
78
98
  # RACK_ENV by default.
99
+ # @return [String]
79
100
  attr_reader :environment
80
101
 
81
102
  # Whether the SDK should run in the debugging mode. Default is false.
82
103
  # If set to true, SDK errors will be logged with backtrace
104
+ # @return [Boolean]
83
105
  attr_accessor :debug
84
106
 
85
107
  # the dsn value, whether it's set via `config.dsn=` or `ENV["SENTRY_DSN"]`
108
+ # @return [String]
86
109
  attr_reader :dsn
87
110
 
88
111
  # Whitelist of enabled_environments that will send notifications to Sentry. Array of Strings.
112
+ # @return [Array<String>]
89
113
  attr_accessor :enabled_environments
90
114
 
91
115
  # Logger 'progname's to exclude from breadcrumbs
116
+ # @return [Array<String>]
92
117
  attr_accessor :exclude_loggers
93
118
 
94
119
  # Array of exception classes that should never be sent. See IGNORE_DEFAULT.
95
120
  # You should probably append to this rather than overwrite it.
121
+ # @return [Array<String>]
96
122
  attr_accessor :excluded_exceptions
97
123
 
98
124
  # Boolean to check nested exceptions when deciding if to exclude. Defaults to true
125
+ # @return [Boolean]
99
126
  attr_accessor :inspect_exception_causes_for_exclusion
100
127
  alias inspect_exception_causes_for_exclusion? inspect_exception_causes_for_exclusion
101
128
 
@@ -106,65 +133,80 @@ module Sentry
106
133
 
107
134
  # Logger used by Sentry. In Rails, this is the Rails logger, otherwise
108
135
  # Sentry provides its own Sentry::Logger.
136
+ # @return [Logger]
109
137
  attr_accessor :logger
110
138
 
111
139
  # Project directory root for in_app detection. Could be Rails root, etc.
112
140
  # Set automatically for Rails.
141
+ # @return [String]
113
142
  attr_accessor :project_root
114
143
 
115
144
  # Insert sentry-trace to outgoing requests' headers
145
+ # @return [Boolean]
116
146
  attr_accessor :propagate_traces
117
147
 
118
148
  # Array of rack env parameters to be included in the event sent to sentry.
149
+ # @return [Array<String>]
119
150
  attr_accessor :rack_env_whitelist
120
151
 
121
152
  # Release tag to be passed with every event sent to Sentry.
122
153
  # We automatically try to set this to a git SHA or Capistrano release.
154
+ # @return [String]
123
155
  attr_accessor :release
124
156
 
125
157
  # The sampling factor to apply to events. A value of 0.0 will not send
126
158
  # any events, and a value of 1.0 will send 100% of events.
159
+ # @return [Float]
127
160
  attr_accessor :sample_rate
128
161
 
129
162
  # Include module versions in reports - boolean.
163
+ # @return [Boolean]
130
164
  attr_accessor :send_modules
131
165
 
132
166
  # When send_default_pii's value is false (default), sensitive information like
133
167
  # - user ip
134
168
  # - user cookie
135
169
  # - request body
170
+ # - query string
136
171
  # will not be sent to Sentry.
172
+ # @return [Boolean]
137
173
  attr_accessor :send_default_pii
138
174
 
139
175
  # Allow to skip Sentry emails within rake tasks
176
+ # @return [Boolean]
140
177
  attr_accessor :skip_rake_integration
141
178
 
142
179
  # IP ranges for trusted proxies that will be skipped when calculating IP address.
143
180
  attr_accessor :trusted_proxies
144
181
 
182
+ # @return [String]
145
183
  attr_accessor :server_name
146
184
 
147
185
  # Return a Transport::Configuration object for transport-related configurations.
186
+ # @return [Transport]
148
187
  attr_reader :transport
149
188
 
150
189
  # Take a float between 0.0 and 1.0 as the sample rate for tracing events (transactions).
190
+ # @return [Float]
151
191
  attr_accessor :traces_sample_rate
152
192
 
153
193
  # Take a Proc that controls the sample rate for every tracing event, e.g.
154
- # ```
155
- # lambda do |tracing_context|
156
- # # tracing_context[:transaction_context] contains the information about the transaction
157
- # # tracing_context[:parent_sampled] contains the transaction's parent's sample decision
158
- # true # return value can be a boolean or a float between 0.0 and 1.0
159
- # end
160
- # ```
194
+ # @example
195
+ # config.traces_sampler = lambda do |tracing_context|
196
+ # # tracing_context[:transaction_context] contains the information about the transaction
197
+ # # tracing_context[:parent_sampled] contains the transaction's parent's sample decision
198
+ # true # return value can be a boolean or a float between 0.0 and 1.0
199
+ # end
200
+ # @return [Proc]
161
201
  attr_accessor :traces_sampler
162
202
 
163
203
  # Send diagnostic client reports about dropped events, true by default
164
204
  # tries to attach to an existing envelope max once every 30s
205
+ # @return [Boolean]
165
206
  attr_accessor :send_client_reports
166
207
 
167
208
  # these are not config options
209
+ # @!visibility private
168
210
  attr_reader :errors, :gem_specs
169
211
 
170
212
  # Most of these errors generate 4XX responses. In general, Sentry clients
@@ -285,11 +327,6 @@ module Sentry
285
327
  Random.rand < sample_rate
286
328
  end
287
329
 
288
- def error_messages
289
- @errors = [@errors[0]] + @errors[1..-1].map(&:downcase) # fix case of all but first
290
- @errors.join(", ")
291
- end
292
-
293
330
  def exception_class_allowed?(exc)
294
331
  if exc.is_a?(Sentry::Error)
295
332
  # Try to prevent error reporting loops
@@ -311,6 +348,17 @@ module Sentry
311
348
  !!((@traces_sample_rate && @traces_sample_rate >= 0.0 && @traces_sample_rate <= 1.0) || @traces_sampler) && sending_allowed?
312
349
  end
313
350
 
351
+ # @return [String, nil]
352
+ def csp_report_uri
353
+ if dsn && dsn.valid?
354
+ uri = dsn.csp_report_uri
355
+ uri += "&sentry_release=#{CGI.escape(release)}" if release && !release.empty?
356
+ uri += "&sentry_environment=#{CGI.escape(environment)}" if environment && !environment.empty?
357
+ uri
358
+ end
359
+ end
360
+
361
+ # @api private
314
362
  def stacktrace_builder
315
363
  @stacktrace_builder ||= StacktraceBuilder.new(
316
364
  project_root: @project_root.to_s,
@@ -321,6 +369,7 @@ module Sentry
321
369
  )
322
370
  end
323
371
 
372
+ # @api private
324
373
  def detect_release
325
374
  return unless sending_allowed?
326
375
 
@@ -333,13 +382,10 @@ module Sentry
333
382
  log_error("Error detecting release", e, debug: debug)
334
383
  end
335
384
 
336
- def csp_report_uri
337
- if dsn && dsn.valid?
338
- uri = dsn.csp_report_uri
339
- uri += "&sentry_release=#{CGI.escape(release)}" if release && !release.empty?
340
- uri += "&sentry_environment=#{CGI.escape(environment)}" if environment && !environment.empty?
341
- uri
342
- end
385
+ # @api private
386
+ def error_messages
387
+ @errors = [@errors[0]] + @errors[1..-1].map(&:downcase) # fix case of all but first
388
+ @errors.join(", ")
343
389
  end
344
390
 
345
391
  private
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  return if Object.method_defined?(:deep_dup)
2
4
 
3
5
  require 'sentry/core_ext/object/duplicable'
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  return if Object.method_defined?(:duplicable?)
3
4
 
4
5
  #########################################
data/lib/sentry/dsn.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "uri"
2
4
 
3
5
  module Sentry
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ # @api private
5
+ class Envelope
6
+ def initialize(headers)
7
+ @headers = headers
8
+ @items = []
9
+ end
10
+
11
+ def add_item(headers, payload)
12
+ @items << [headers, payload]
13
+ end
14
+
15
+ def to_s
16
+ payload = @items.map do |item_headers, item_payload|
17
+ <<~ENVELOPE
18
+ #{JSON.generate(item_headers)}
19
+ #{JSON.generate(item_payload)}
20
+ ENVELOPE
21
+ end.join("\n")
22
+
23
+ "#{JSON.generate(@headers)}\n#{payload}"
24
+ end
25
+ end
26
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class Error < StandardError
3
5
  end
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
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  module Integrable
3
5
  def register_integration(name:, version:)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class Interface
3
5
  def self.inherited(klass)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class ExceptionInterface < Interface
3
5
  def initialize(values:)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "sentry/utils/exception_cause_chain"
2
4
 
3
5
  module Sentry
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class StacktraceInterface
3
5
  attr_reader :frames
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class StacktraceBuilder
3
5
  attr_reader :project_root, :app_dirs_pattern, :linecache, :context_lines, :backtrace_cleanup_callback
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class ThreadsInterface
3
5
  def initialize(crashed: false, stacktrace: nil)
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
4
+ # @api private
2
5
  class LineCache
3
6
  def initialize
4
7
  @cache = {}
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "net/http"
2
4
 
3
5
  module Sentry
6
+ # @api private
4
7
  module Net
5
8
  module HTTP
6
9
  OP_NAME = "net.http"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  module Rack
3
5
  class CaptureExceptions
data/lib/sentry/rack.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rack'
2
4
 
3
5
  require 'sentry/rack/capture_exceptions'
data/lib/sentry/rake.rb CHANGED
@@ -1,11 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rake"
2
4
  require "rake/task"
3
5
 
4
6
  module Sentry
5
7
  module Rake
6
8
  module Application
9
+ # @api private
7
10
  def display_error_message(ex)
8
- Sentry.capture_exception(ex, hint: { background: false }) do |scope|
11
+ Sentry.capture_exception(ex) do |scope|
9
12
  task_name = top_level_tasks.join(' ')
10
13
  scope.set_transaction_name(task_name)
11
14
  scope.set_tag("rake_task", task_name)
@@ -16,16 +19,23 @@ module Sentry
16
19
  end
17
20
 
18
21
  module Task
22
+ # @api private
19
23
  def execute(args=nil)
20
24
  return super unless Sentry.initialized? && Sentry.get_current_hub
21
25
 
22
- Sentry.get_current_hub.with_background_worker_disabled do
23
- super
24
- end
26
+ super
25
27
  end
26
28
  end
27
29
  end
28
30
  end
29
31
 
30
- Rake::Application.prepend(Sentry::Rake::Application)
31
- Rake::Task.prepend(Sentry::Rake::Task)
32
+ # @api private
33
+ module Rake
34
+ class Application
35
+ prepend(Sentry::Rake::Application)
36
+ end
37
+
38
+ class Task
39
+ prepend(Sentry::Rake::Task)
40
+ end
41
+ end
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
4
+ # @api private
2
5
  class ReleaseDetector
3
6
  class << self
4
7
  def detect_release(project_root:, running_on_heroku:)
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
- @extra.merge!(key => value)
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
- @tags.merge!(key => value)
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
- @contexts.merge!(key => value)
138
+ set_contexts(key => value)
135
139
  end
136
140
 
137
141
  def set_level(level)
data/lib/sentry/span.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "securerandom"
3
4
 
4
5
  module Sentry
@@ -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(
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class Transport
3
5
  class Configuration
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  class DummyTransport < Transport
3
5
  attr_accessor :events
@@ -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
- (@transport_configuration.ssl || {}).merge(
143
- :verify => @transport_configuration.ssl_verification,
144
- :ca_file => @transport_configuration.ssl_ca_file
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
@@ -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
@@ -103,31 +106,29 @@ module Sentry
103
106
  def encode(event)
104
107
  # Convert to hash
105
108
  event_payload = event.to_hash
106
-
107
109
  event_id = event_payload[:event_id] || event_payload["event_id"]
108
110
  item_type = get_item_type(event_payload)
109
111
 
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
- }
116
-
117
- event_header = { type: item_type, content_type: 'application/json' }
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
+ )
118
120
 
119
- envelope = <<~ENVELOPE
120
- #{JSON.generate(envelope_header)}
121
- #{JSON.generate(event_header)}
122
- #{JSON.generate(event_payload)}
123
- ENVELOPE
121
+ envelope.add_item(
122
+ { type: item_type, content_type: 'application/json' },
123
+ event_payload
124
+ )
124
125
 
125
- client_report = fetch_pending_client_report
126
- envelope << client_report if client_report
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
127
128
 
128
129
  log_info("Sending envelope [#{item_type}] #{event_id} to Sentry")
129
130
 
130
- envelope
131
+ envelope.to_s
131
132
  end
132
133
 
133
134
  def record_lost_event(reason, item_type)
@@ -159,21 +160,15 @@ module Sentry
159
160
  end
160
161
 
161
162
  item_header = { type: 'client_report' }
162
-
163
163
  item_payload = {
164
164
  timestamp: Sentry.utc_now.iso8601,
165
165
  discarded_events: discarded_events_hash
166
166
  }
167
167
 
168
- client_report_item = <<~CLIENT_REPORT_ITEM
169
- #{JSON.generate(item_header)}
170
- #{JSON.generate(item_payload)}
171
- CLIENT_REPORT_ITEM
172
-
173
168
  @discarded_events = Hash.new(0)
174
169
  @last_client_report_sent = Time.now
175
170
 
176
- client_report_item
171
+ [item_header, item_payload]
177
172
  end
178
173
  end
179
174
  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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Sentry
2
4
  module LoggingHelper
3
5
  def log_error(message, exception, debug: false)
@@ -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.8.2"
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"
@@ -37,6 +39,7 @@ module Sentry
37
39
  THREAD_LOCAL = :sentry_hub
38
40
 
39
41
  class << self
42
+ # @!visibility private
40
43
  def exception_locals_tp
41
44
  @exception_locals_tp ||= TracePoint.new(:raise) do |tp|
42
45
  exception = tp.raised_exception
@@ -53,46 +56,60 @@ module Sentry
53
56
  end
54
57
  end
55
58
 
59
+ # @!attribute [rw] background_worker
60
+ # @return [BackgroundWorker]
56
61
  attr_accessor :background_worker
57
62
 
58
63
  ##### Patch Registration #####
59
- #
64
+
65
+ # @!visibility private
60
66
  def register_patch(&block)
61
67
  registered_patches << block
62
68
  end
63
69
 
70
+ # @!visibility private
64
71
  def apply_patches(config)
65
72
  registered_patches.each do |patch|
66
73
  patch.call(config)
67
74
  end
68
75
  end
69
76
 
77
+ # @!visibility private
70
78
  def registered_patches
71
79
  @registered_patches ||= []
72
80
  end
73
81
 
74
82
  ##### Integrations #####
75
- #
83
+
76
84
  # Returns a hash that contains all the integrations that have been registered to the main SDK.
85
+ #
86
+ # @return [Hash{String=>Hash}]
77
87
  def integrations
78
88
  @integrations ||= {}
79
89
  end
80
90
 
81
91
  # Registers the SDK integration with its name and version.
92
+ #
93
+ # @param name [String] name of the integration
94
+ # @param version [String] version of the integration
82
95
  def register_integration(name, version)
83
96
  meta = { name: "sentry.ruby.#{name}", version: version }.freeze
84
97
  integrations[name.to_s] = meta
85
98
  end
86
99
 
87
100
  ##### Method Delegation #####
88
- #
101
+
89
102
  extend Forwardable
90
103
 
91
104
  def_delegators :get_current_client, :configuration, :send_event
92
105
  def_delegators :get_current_scope, :set_tags, :set_extras, :set_user, :set_context
93
106
 
94
107
  ##### Main APIs #####
108
+
109
+ # Initializes the SDK with given configuration.
95
110
  #
111
+ # @yieldparam config [Configuration]
112
+ # @return [void]
96
113
  def init(&block)
97
114
  config = Configuration.new
98
115
  yield(config) if block_given?
@@ -108,26 +125,42 @@ module Sentry
108
125
  if config.capture_exception_frame_locals
109
126
  exception_locals_tp.enable
110
127
  end
128
+
129
+ at_exit do
130
+ @background_worker.shutdown
131
+ end
132
+ end
133
+
134
+ # Returns true if the SDK is initialized.
135
+ #
136
+ # @return [Boolean]
137
+ def initialized?
138
+ !!@main_hub
111
139
  end
112
140
 
113
141
  # Returns an uri for security policy reporting that's generated from the given DSN
114
142
  # (To learn more about security policy reporting: https://docs.sentry.io/product/security-policy-reporting/)
115
143
  #
116
144
  # It returns nil if
145
+ # - The SDK is not initialized yet.
146
+ # - The DSN is not provided or is invalid.
117
147
  #
118
- # 1. The SDK is not initialized yet.
119
- # 2. The DSN is not provided or is invalid.
148
+ # @return [String, nil]
120
149
  def csp_report_uri
121
150
  return unless initialized?
122
151
  configuration.csp_report_uri
123
152
  end
124
153
 
125
154
  # Returns the main thread's active hub.
155
+ #
156
+ # @return [Hub]
126
157
  def get_main_hub
127
158
  @main_hub
128
159
  end
129
160
 
130
161
  # Takes an instance of Sentry::Breadcrumb and stores it to the current active scope.
162
+ #
163
+ # @return [Breadcrumb, nil]
131
164
  def add_breadcrumb(breadcrumb, **options)
132
165
  get_current_hub&.add_breadcrumb(breadcrumb, **options)
133
166
  end
@@ -135,6 +168,8 @@ module Sentry
135
168
  # Returns the current active hub.
136
169
  # If the current thread doesn't have an active hub, it will clone the main thread's active hub,
137
170
  # stores it in the current thread, and then returns it.
171
+ #
172
+ # @return [Hub]
138
173
  def get_current_hub
139
174
  # we need to assign a hub to the current thread if it doesn't have one yet
140
175
  #
@@ -145,85 +180,105 @@ module Sentry
145
180
  end
146
181
 
147
182
  # Returns the current active client.
183
+ # @return [Client, nil]
148
184
  def get_current_client
149
185
  get_current_hub&.current_client
150
186
  end
151
187
 
152
188
  # Returns the current active scope.
189
+ #
190
+ # @return [Scope, nil]
153
191
  def get_current_scope
154
192
  get_current_hub&.current_scope
155
193
  end
156
194
 
157
195
  # Clones the main thread's active hub and stores it to the current thread.
196
+ #
197
+ # @return [void]
158
198
  def clone_hub_to_current_thread
159
199
  Thread.current.thread_variable_set(THREAD_LOCAL, get_main_hub.clone)
160
200
  end
161
201
 
162
202
  # Takes a block and yields the current active scope.
163
203
  #
164
- # ```ruby
165
- # Sentry.configure_scope do |scope|
166
- # scope.set_tags(foo: "bar")
167
- # end
204
+ # @example
205
+ # Sentry.configure_scope do |scope|
206
+ # scope.set_tags(foo: "bar")
207
+ # end
168
208
  #
169
- # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
170
- # ```
209
+ # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
171
210
  #
211
+ # @yieldparam scope [Scope]
212
+ # @return [void]
172
213
  def configure_scope(&block)
173
214
  get_current_hub&.configure_scope(&block)
174
215
  end
175
216
 
176
217
  # Takes a block and yields a temporary scope.
177
218
  # 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:
219
+ # scope inside the block.
179
220
  #
180
- # ```ruby
181
- # Sentry.configure_scope do |scope|
182
- # scope.set_tags(foo: "bar")
183
- # end
221
+ # @example
222
+ # Sentry.configure_scope do |scope|
223
+ # scope.set_tags(foo: "bar")
224
+ # end
184
225
  #
185
- # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
226
+ # Sentry.capture_message("test message") # this event will have tags { foo: "bar" }
186
227
  #
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
228
+ # Sentry.with_scope do |temp_scope|
229
+ # temp_scope.set_tags(foo: "baz")
230
+ # Sentry.capture_message("test message 2") # this event will have tags { foo: "baz" }
231
+ # end
191
232
  #
192
- # Sentry.capture_message("test message 3") # this event will have tags { foo: "bar" }
193
- # ```
233
+ # Sentry.capture_message("test message 3") # this event will have tags { foo: "bar" }
194
234
  #
235
+ # @yieldparam scope [Scope]
236
+ # @return [void]
195
237
  def with_scope(&block)
196
238
  get_current_hub&.with_scope(&block)
197
239
  end
198
240
 
199
241
  # Takes an exception and reports it to Sentry via the currently active hub.
242
+ #
243
+ # @yieldparam scope [Scope]
244
+ # @return [Event, nil]
200
245
  def capture_exception(exception, **options, &block)
201
246
  get_current_hub&.capture_exception(exception, **options, &block)
202
247
  end
203
248
 
204
249
  # Takes a message string and reports it to Sentry via the currently active hub.
250
+ #
251
+ # @yieldparam scope [Scope]
252
+ # @return [Event, nil]
205
253
  def capture_message(message, **options, &block)
206
254
  get_current_hub&.capture_message(message, **options, &block)
207
255
  end
208
256
 
209
257
  # Takes an instance of Sentry::Event and dispatches it to the currently active hub.
258
+ #
259
+ # @return [Event, nil]
210
260
  def capture_event(event)
211
261
  get_current_hub&.capture_event(event)
212
262
  end
213
263
 
214
264
  # Takes or initializes a new Sentry::Transaction and makes a sampling decision for it.
265
+ #
266
+ # @return [Transaction, nil]
215
267
  def start_transaction(**options)
216
268
  get_current_hub&.start_transaction(**options)
217
269
  end
218
270
 
219
271
  # Returns the id of the lastly reported Sentry::Event.
272
+ #
273
+ # @return [String, nil]
220
274
  def last_event_id
221
275
  get_current_hub&.last_event_id
222
276
  end
223
277
 
224
278
 
225
279
  ##### Helpers #####
226
- #
280
+
281
+ # @!visibility private
227
282
  def sys_command(command)
228
283
  result = `#{command} 2>&1` rescue nil
229
284
  return if result.nil? || result.empty? || ($CHILD_STATUS && $CHILD_STATUS.exitstatus != 0)
@@ -231,18 +286,17 @@ module Sentry
231
286
  result.strip
232
287
  end
233
288
 
234
- def initialized?
235
- !!@main_hub
236
- end
237
-
289
+ # @!visibility private
238
290
  def logger
239
291
  configuration.logger
240
292
  end
241
293
 
294
+ # @!visibility private
242
295
  def sdk_meta
243
296
  META
244
297
  end
245
298
 
299
+ # @!visibility private
246
300
  def utc_now
247
301
  Time.now.utc
248
302
  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.8.2
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-04 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