sentry-ruby 5.14.0 → 5.15.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95fd53222ce5360d32645f0bc7577792bdef0a02b9e4b8de27555eabd2ef1844
4
- data.tar.gz: e5eb696315a22747051e5bbdeac314c5ae103cabd59d3fb266b16b0b22345611
3
+ metadata.gz: 8ad04d5359f4cc44d2a2e398d1083b72f11c96efabc4a3b2148327261e327a20
4
+ data.tar.gz: 2800581dce649c81f5a17464f3b5619158900d8c5eb23e35347507dddb594b04
5
5
  SHA512:
6
- metadata.gz: f18df0d05208c0a03352501b4b746f6ccc74799b234198b67b35e709539fde52aa36c56a6297510e8e9e1dc8a62658ac5d81e0023c5935de455effc16ee824fe
7
- data.tar.gz: 47f5db68454ab971d92df8c7fbd95846830edfe09b6b2ea40fef1f5ab39a9db922a5564abe45b29fb55df729bdf53bb1632c566c93b8b7f0d1c96e00c441d0dc
6
+ metadata.gz: d8bce6cfd5f48acb743b6018e5d34e4832de9eb05e68a0c114fd90bb13e8c80fcf6da97cb8e80a64d78e930b3ee6b8ee22711c2efa2e018f43b33d0ff09cf68b
7
+ data.tar.gz: 1f9749bf1ccee5a541c4949dbf2b0f79da9508f6a86aa3d603811b252a49f4ca3054e91dfa7a0e93dac723965e8e316f56c8433ddf796c7d8f38069075b80268
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
@@ -142,6 +142,14 @@ module Sentry
142
142
  # @return [Boolean]
143
143
  attr_accessor :include_local_variables
144
144
 
145
+ # Whether to capture events and traces into Spotlight. Default is false.
146
+ # If you set this to true, Sentry will send events and traces to the local
147
+ # Sidecar proxy at http://localhost:8969/stream.
148
+ # If you want to use a different Sidecar proxy address, set this to String
149
+ # with the proxy URL.
150
+ # @return [Boolean, String]
151
+ attr_accessor :spotlight
152
+
145
153
  # @deprecated Use {#include_local_variables} instead.
146
154
  alias_method :capture_exception_frame_locals, :include_local_variables
147
155
 
@@ -344,6 +352,7 @@ module Sentry
344
352
  self.auto_session_tracking = true
345
353
  self.trusted_proxies = []
346
354
  self.dsn = ENV['SENTRY_DSN']
355
+ self.spotlight = false
347
356
  self.server_name = server_name_from_env
348
357
  self.instrumenter = :sentry
349
358
  self.trace_propagation_targets = [PROPAGATION_TARGETS_MATCH_ALL]
@@ -451,7 +460,7 @@ module Sentry
451
460
  def sending_allowed?
452
461
  @errors = []
453
462
 
454
- valid? && capture_in_environment?
463
+ spotlight || (valid? && capture_in_environment?)
455
464
  end
456
465
 
457
466
  def sample_allowed?
@@ -44,7 +44,7 @@ module Sentry
44
44
  prepend Patch
45
45
  end
46
46
 
47
- def sentry_monitor_slug
47
+ def sentry_monitor_slug(name: self.name)
48
48
  @sentry_monitor_slug ||= begin
49
49
  slug = name.gsub('::', '-').downcase
50
50
  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.0"
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.0
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-05 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