sentry-ruby 5.14.0 → 5.15.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95fd53222ce5360d32645f0bc7577792bdef0a02b9e4b8de27555eabd2ef1844
4
- data.tar.gz: e5eb696315a22747051e5bbdeac314c5ae103cabd59d3fb266b16b0b22345611
3
+ metadata.gz: 76add924de8ccd4132764766cf92d057a7e4ee9554790688e2c2597b569097c2
4
+ data.tar.gz: 856d0936cb2ad123b3ca632e63cb8cf951e13f90755386dcb67b3cc63760ee69
5
5
  SHA512:
6
- metadata.gz: f18df0d05208c0a03352501b4b746f6ccc74799b234198b67b35e709539fde52aa36c56a6297510e8e9e1dc8a62658ac5d81e0023c5935de455effc16ee824fe
7
- data.tar.gz: 47f5db68454ab971d92df8c7fbd95846830edfe09b6b2ea40fef1f5ab39a9db922a5564abe45b29fb55df729bdf53bb1632c566c93b8b7f0d1c96e00c441d0dc
6
+ metadata.gz: 245ee7955da8f38b12db8e2ed18802fbb63a74efd5853968a91fe5e45551f17aa0dd95e8dd07458e1374817b33b3cfc6ab752406fea9f16f55a4027d204d622b
7
+ data.tar.gz: 7fd7cadec651b7464409154ed26eb41852bb2cfbf89bb3f57cecc102058a9b8498bf9f29670ebcd6c25048a1a353878adaadc8a8c1b816baf5b08baf0c380e54
data/Gemfile CHANGED
@@ -12,28 +12,9 @@ gem "redis", "~> #{redis_rb_version}"
12
12
 
13
13
  gem "puma"
14
14
 
15
- gem "rake", "~> 12.0"
16
- gem "rspec", "~> 3.0"
17
- gem "rspec-retry"
18
15
  gem "timecop"
19
- gem "simplecov"
20
- gem "simplecov-cobertura", "~> 1.4"
21
- gem "rexml"
22
16
  gem "stackprof" unless RUBY_PLATFORM == "java"
23
17
 
24
- ruby_version = Gem::Version.new(RUBY_VERSION)
25
-
26
- if ruby_version >= Gem::Version.new("2.6.0")
27
- gem "debug", github: "ruby/debug", platform: :ruby
28
- gem "irb"
29
-
30
- if ruby_version >= Gem::Version.new("3.0.0")
31
- gem "ruby-lsp-rspec"
32
- end
33
- end
34
-
35
- gem "pry"
36
-
37
18
  gem "benchmark-ips"
38
19
  gem "benchmark_driver"
39
20
  gem "benchmark-ipsa"
@@ -41,3 +22,5 @@ gem "benchmark-memory"
41
22
 
42
23
  gem "yard", github: "lsegal/yard"
43
24
  gem "webrick"
25
+
26
+ eval_gemfile File.expand_path("../Gemfile", __dir__)
@@ -13,10 +13,12 @@ module Sentry
13
13
  attr_reader :logger
14
14
  attr_accessor :shutdown_timeout
15
15
 
16
+ DEFAULT_MAX_QUEUE = 30
17
+
16
18
  def initialize(configuration)
17
- @max_queue = 30
18
19
  @shutdown_timeout = 1
19
20
  @number_of_threads = configuration.background_worker_threads
21
+ @max_queue = configuration.background_worker_max_queue
20
22
  @logger = configuration.logger
21
23
  @debug = configuration.debug
22
24
  @shutdown_callback = nil
data/lib/sentry/client.rb CHANGED
@@ -10,6 +10,10 @@ module Sentry
10
10
  # @return [Transport]
11
11
  attr_reader :transport
12
12
 
13
+ # The Transport object that'll send events for the client.
14
+ # @return [SpotlightTransport, nil]
15
+ attr_reader :spotlight_transport
16
+
13
17
  # @!macro configuration
14
18
  attr_reader :configuration
15
19
 
@@ -32,6 +36,8 @@ module Sentry
32
36
  DummyTransport.new(configuration)
33
37
  end
34
38
  end
39
+
40
+ @spotlight_transport = SpotlightTransport.new(configuration) if configuration.spotlight
35
41
  end
36
42
 
37
43
  # Applies the given scope's data to the event and sends it to Sentry.
@@ -167,6 +173,7 @@ module Sentry
167
173
  end
168
174
 
169
175
  transport.send_event(event)
176
+ spotlight_transport&.send_event(event)
170
177
 
171
178
  event
172
179
  rescue => e
@@ -40,6 +40,13 @@ module Sentry
40
40
  # @return [Integer]
41
41
  attr_accessor :background_worker_threads
42
42
 
43
+ # The maximum queue size for the background worker.
44
+ # Jobs will be rejected above this limit.
45
+ #
46
+ # Default is {BackgroundWorker::DEFAULT_MAX_QUEUE}.
47
+ # @return [Integer]
48
+ attr_accessor :background_worker_max_queue
49
+
43
50
  # a proc/lambda that takes an array of stack traces
44
51
  # it'll be used to silence (reduce) backtrace of the exception
45
52
  #
@@ -142,6 +149,14 @@ module Sentry
142
149
  # @return [Boolean]
143
150
  attr_accessor :include_local_variables
144
151
 
152
+ # Whether to capture events and traces into Spotlight. Default is false.
153
+ # If you set this to true, Sentry will send events and traces to the local
154
+ # Sidecar proxy at http://localhost:8969/stream.
155
+ # If you want to use a different Sidecar proxy address, set this to String
156
+ # with the proxy URL.
157
+ # @return [Boolean, String]
158
+ attr_accessor :spotlight
159
+
145
160
  # @deprecated Use {#include_local_variables} instead.
146
161
  alias_method :capture_exception_frame_locals, :include_local_variables
147
162
 
@@ -321,6 +336,7 @@ module Sentry
321
336
  self.app_dirs_pattern = nil
322
337
  self.debug = false
323
338
  self.background_worker_threads = Concurrent.processor_count
339
+ self.background_worker_max_queue = BackgroundWorker::DEFAULT_MAX_QUEUE
324
340
  self.backtrace_cleanup_callback = nil
325
341
  self.max_breadcrumbs = BreadcrumbBuffer::DEFAULT_SIZE
326
342
  self.breadcrumbs_logger = []
@@ -344,6 +360,7 @@ module Sentry
344
360
  self.auto_session_tracking = true
345
361
  self.trusted_proxies = []
346
362
  self.dsn = ENV['SENTRY_DSN']
363
+ self.spotlight = false
347
364
  self.server_name = server_name_from_env
348
365
  self.instrumenter = :sentry
349
366
  self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
@@ -451,7 +468,7 @@ module Sentry
451
468
  def sending_allowed?
452
469
  @errors = []
453
470
 
454
- valid? && capture_in_environment?
471
+ spotlight || (valid? && capture_in_environment?)
455
472
  end
456
473
 
457
474
  def sample_allowed?
@@ -4,7 +4,7 @@ module Sentry
4
4
  MAX_SLUG_LENGTH = 50
5
5
 
6
6
  module Patch
7
- def perform(*args)
7
+ def perform(*args, **opts)
8
8
  slug = self.class.sentry_monitor_slug
9
9
  monitor_config = self.class.sentry_monitor_config
10
10
 
@@ -13,7 +13,8 @@ module Sentry
13
13
  monitor_config: monitor_config)
14
14
 
15
15
  start = Sentry.utc_now.to_i
16
- ret = super
16
+ # need to do this on ruby <= 2.6 sadly
17
+ ret = method(:perform).super_method.arity == 0 ? super() : super
17
18
  duration = Sentry.utc_now.to_i - start
18
19
 
19
20
  Sentry.capture_check_in(slug,
@@ -44,7 +45,7 @@ module Sentry
44
45
  prepend Patch
45
46
  end
46
47
 
47
- def sentry_monitor_slug
48
+ def sentry_monitor_slug(name: self.name)
48
49
  @sentry_monitor_slug ||= begin
49
50
  slug = name.gsub('::', '-').downcase
50
51
  slug[-MAX_SLUG_LENGTH..-1] || slug
@@ -14,11 +14,19 @@ module Sentry
14
14
  RATE_LIMIT_HEADER = "x-sentry-rate-limits"
15
15
  USER_AGENT = "sentry-ruby/#{Sentry::VERSION}"
16
16
 
17
+ # The list of errors ::Net::HTTP is known to raise
18
+ # See https://github.com/ruby/ruby/blob/b0c639f249165d759596f9579fa985cb30533de6/lib/bundler/fetcher.rb#L281-L286
19
+ HTTP_ERRORS = [
20
+ Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH,
21
+ Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN,
22
+ Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError,
23
+ Zlib::BufError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED
24
+ ].freeze
25
+
26
+
17
27
  def initialize(*args)
18
28
  super
19
- @endpoint = @dsn.envelope_endpoint
20
-
21
- log_debug("Sentry HTTP Transport will connect to #{@dsn.server}")
29
+ log_debug("Sentry HTTP Transport will connect to #{@dsn.server}") if @dsn
22
30
  end
23
31
 
24
32
  def send_data(data)
@@ -32,12 +40,14 @@ module Sentry
32
40
  headers = {
33
41
  'Content-Type' => CONTENT_TYPE,
34
42
  'Content-Encoding' => encoding,
35
- 'X-Sentry-Auth' => generate_auth_header,
36
43
  'User-Agent' => USER_AGENT
37
44
  }
38
45
 
46
+ auth_header = generate_auth_header
47
+ headers['X-Sentry-Auth'] = auth_header if auth_header
48
+
39
49
  response = conn.start do |http|
40
- request = ::Net::HTTP::Post.new(@endpoint, headers)
50
+ request = ::Net::HTTP::Post.new(endpoint, headers)
41
51
  request.body = data
42
52
  http.request(request)
43
53
  end
@@ -58,8 +68,52 @@ module Sentry
58
68
 
59
69
  raise Sentry::ExternalError, error_info
60
70
  end
61
- rescue SocketError => e
62
- raise Sentry::ExternalError.new(e.message)
71
+ rescue SocketError, *HTTP_ERRORS => e
72
+ on_error if respond_to?(:on_error)
73
+ raise Sentry::ExternalError.new(e&.message)
74
+ end
75
+
76
+ def endpoint
77
+ @dsn.envelope_endpoint
78
+ end
79
+
80
+ def generate_auth_header
81
+ return nil unless @dsn
82
+
83
+ now = Sentry.utc_now.to_i
84
+ fields = {
85
+ 'sentry_version' => PROTOCOL_VERSION,
86
+ 'sentry_client' => USER_AGENT,
87
+ 'sentry_timestamp' => now,
88
+ 'sentry_key' => @dsn.public_key
89
+ }
90
+ fields['sentry_secret'] = @dsn.secret_key if @dsn.secret_key
91
+ 'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
92
+ end
93
+
94
+ def conn
95
+ server = URI(@dsn.server)
96
+
97
+ # connection respects proxy setting from @transport_configuration, or environment variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY)
98
+ # Net::HTTP will automatically read the env vars.
99
+ # See https://ruby-doc.org/3.2.2/stdlibs/net/Net/HTTP.html#class-Net::HTTP-label-Proxies
100
+ connection =
101
+ if proxy = normalize_proxy(@transport_configuration.proxy)
102
+ ::Net::HTTP.new(server.hostname, server.port, proxy[:uri].hostname, proxy[:uri].port, proxy[:user], proxy[:password])
103
+ else
104
+ ::Net::HTTP.new(server.hostname, server.port)
105
+ end
106
+
107
+ connection.use_ssl = server.scheme == "https"
108
+ connection.read_timeout = @transport_configuration.timeout
109
+ connection.write_timeout = @transport_configuration.timeout if connection.respond_to?(:write_timeout)
110
+ connection.open_timeout = @transport_configuration.open_timeout
111
+
112
+ ssl_configuration.each do |key, value|
113
+ connection.send("#{key}=", value)
114
+ end
115
+
116
+ connection
63
117
  end
64
118
 
65
119
  private
@@ -126,31 +180,6 @@ module Sentry
126
180
  @transport_configuration.encoding == GZIP_ENCODING && data.bytesize >= GZIP_THRESHOLD
127
181
  end
128
182
 
129
- def conn
130
- server = URI(@dsn.server)
131
-
132
- # connection respects proxy setting from @transport_configuration, or environment variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY)
133
- # Net::HTTP will automatically read the env vars.
134
- # See https://ruby-doc.org/3.2.2/stdlibs/net/Net/HTTP.html#class-Net::HTTP-label-Proxies
135
- connection =
136
- if proxy = normalize_proxy(@transport_configuration.proxy)
137
- ::Net::HTTP.new(server.hostname, server.port, proxy[:uri].hostname, proxy[:uri].port, proxy[:user], proxy[:password])
138
- else
139
- ::Net::HTTP.new(server.hostname, server.port)
140
- end
141
-
142
- connection.use_ssl = server.scheme == "https"
143
- connection.read_timeout = @transport_configuration.timeout
144
- connection.write_timeout = @transport_configuration.timeout if connection.respond_to?(:write_timeout)
145
- connection.open_timeout = @transport_configuration.open_timeout
146
-
147
- ssl_configuration.each do |key, value|
148
- connection.send("#{key}=", value)
149
- end
150
-
151
- connection
152
- end
153
-
154
183
  # @param proxy [String, URI, Hash] Proxy config value passed into `config.transport`.
155
184
  # Accepts either a URI formatted string, URI, or a hash with the `uri`, `user`, and `password` keys.
156
185
  # @return [Hash] Normalized proxy config that will be passed into `Net::HTTP`
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "zlib"
5
+
6
+ module Sentry
7
+ # Designed to just report events to Spotlight in development.
8
+ class SpotlightTransport < HTTPTransport
9
+ DEFAULT_SIDECAR_URL = "http://localhost:8969/stream"
10
+ MAX_FAILED_REQUESTS = 3
11
+
12
+ def initialize(configuration)
13
+ super
14
+ @sidecar_url = configuration.spotlight.is_a?(String) ? configuration.spotlight : DEFAULT_SIDECAR_URL
15
+ @failed = 0
16
+ @logged = false
17
+
18
+ log_debug("[Spotlight] initialized for url #{@sidecar_url}")
19
+ end
20
+
21
+ def endpoint
22
+ "/stream"
23
+ end
24
+
25
+ def send_data(data)
26
+ if @failed >= MAX_FAILED_REQUESTS
27
+ unless @logged
28
+ log_debug("[Spotlight] disabling because of too many request failures")
29
+ @logged = true
30
+ end
31
+
32
+ return
33
+ end
34
+
35
+ super
36
+ end
37
+
38
+ def on_error
39
+ @failed += 1
40
+ end
41
+
42
+ # Similar to HTTPTransport connection, but does not support Proxy and SSL
43
+ def conn
44
+ sidecar = URI(@sidecar_url)
45
+ connection = ::Net::HTTP.new(sidecar.hostname, sidecar.port, nil)
46
+ connection.use_ssl = false
47
+ connection
48
+ end
49
+ end
50
+ end
@@ -119,18 +119,6 @@ module Sentry
119
119
  !!delay && delay > Time.now
120
120
  end
121
121
 
122
- def generate_auth_header
123
- now = Sentry.utc_now.to_i
124
- fields = {
125
- 'sentry_version' => PROTOCOL_VERSION,
126
- 'sentry_client' => USER_AGENT,
127
- 'sentry_timestamp' => now,
128
- 'sentry_key' => @dsn.public_key
129
- }
130
- fields['sentry_secret'] = @dsn.secret_key if @dsn.secret_key
131
- 'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
132
- end
133
-
134
122
  def envelope_from_event(event)
135
123
  # Convert to hash
136
124
  event_payload = event.to_hash
@@ -220,3 +208,4 @@ end
220
208
 
221
209
  require "sentry/transport/dummy_transport"
222
210
  require "sentry/transport/http_transport"
211
+ require "sentry/transport/spotlight_transport"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentry
4
- VERSION = "5.14.0"
4
+ VERSION = "5.15.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.14.0
4
+ version: 5.15.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sentry Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-27 00:00:00.000000000 Z
11
+ date: 2023-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -100,6 +100,7 @@ files:
100
100
  - lib/sentry/transport/configuration.rb
101
101
  - lib/sentry/transport/dummy_transport.rb
102
102
  - lib/sentry/transport/http_transport.rb
103
+ - lib/sentry/transport/spotlight_transport.rb
103
104
  - lib/sentry/utils/argument_checking_helper.rb
104
105
  - lib/sentry/utils/custom_inspection.rb
105
106
  - lib/sentry/utils/encoding_helper.rb