sentry-ruby-core 4.9.2 → 5.1.0

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: 4cf9f47960b6d555a19ee4859d686f535b238a0046999039b1bd24958d8a65cf
4
- data.tar.gz: 7c99f67a943ed2cd8cc5f2c006aeb8b9dd89664997abacb83133d11ebeca2904
3
+ metadata.gz: e8b9d0c43497ccc151613d208b6e9a51489586a41cbb7849cbcfcd3e5795765f
4
+ data.tar.gz: 79e7e9f621b2fe8bfc1c1dc292a16392e499925c13bdc1c31c3f8e05240f42e0
5
5
  SHA512:
6
- metadata.gz: 4e049ffe7513c8f78274093ff3f4f2ef6e754b442611352525453d9c040fb30391e63fd5e668c83e464e3b3293d003aa4944f00b66741a66176ad913a47949db
7
- data.tar.gz: 8f0b9a6cef78cdab2804ffa2a3dd6de029672430ade59d907f6c1d60f6143817445d5c79524e0a1a66e95ffe0c2acba2b0a93af844057b172ec1fbb8b8fc420f
6
+ metadata.gz: 3def5710a658f0365dbe11292f548aafcaf6d467d04abd5e0973035c5c3243307d49347b829ae0aa93d459c2bf4036813ec2a4589471c8da21d438318144c0aa
7
+ data.tar.gz: 99eab89037a4e468c7bb257d33aaf85ec8830102aa233a9af4c5091c92d67726f4ffab47b3eeedba07f079b4b3600145458e9283274532b534824acd21236617
data/Gemfile CHANGED
@@ -9,6 +9,7 @@ gem "rake", "~> 12.0"
9
9
  gem "rspec", "~> 3.0"
10
10
  gem "rspec-retry"
11
11
  gem "webmock"
12
+ gem "fakeredis"
12
13
  gem "timecop"
13
14
  gem 'simplecov'
14
15
  gem "simplecov-cobertura", "~> 1.4"
data/lib/sentry/client.rb CHANGED
@@ -108,6 +108,7 @@ module Sentry
108
108
  event.contexts.merge!(trace: transaction.get_trace_context)
109
109
  event.timestamp = transaction.timestamp
110
110
  event.start_timestamp = transaction.start_timestamp
111
+ event.tags = transaction.tags
111
112
 
112
113
  finished_spans = transaction.span_recorder.spans.select { |span| span.timestamp && span != transaction }
113
114
  event.spans = finished_spans.map(&:to_hash)
@@ -75,6 +75,7 @@ module Sentry
75
75
  # An array of breadcrumbs loggers to be used. Available options are:
76
76
  # - :sentry_logger
77
77
  # - :http_logger
78
+ # - :redis_logger
78
79
  #
79
80
  # And if you also use sentry-rails:
80
81
  # - :active_support_logger
data/lib/sentry/hub.rb CHANGED
@@ -102,7 +102,10 @@ module Sentry
102
102
 
103
103
  return unless event
104
104
 
105
- capture_event(event, **options, &block)
105
+ capture_event(event, **options, &block).tap do
106
+ # mark the exception as captured so we can use this information to avoid duplicated capturing
107
+ exception.instance_variable_set(:@__sentry_captured, true)
108
+ end
106
109
  end
107
110
 
108
111
  def capture_message(message, **options, &block)
@@ -62,7 +62,7 @@ module Sentry
62
62
  self.url = request.scheme && request.url.split('?').first
63
63
  self.method = request.request_method
64
64
 
65
- self.headers = filter_and_format_headers(env)
65
+ self.headers = filter_and_format_headers(env, send_default_pii)
66
66
  self.env = filter_and_format_env(env, rack_env_whitelist)
67
67
  end
68
68
 
@@ -81,13 +81,14 @@ module Sentry
81
81
  e.message
82
82
  end
83
83
 
84
- def filter_and_format_headers(env)
84
+ def filter_and_format_headers(env, send_default_pii)
85
85
  env.each_with_object({}) do |(key, value), memo|
86
86
  begin
87
87
  key = key.to_s # rack env can contain symbols
88
88
  next memo['X-Request-Id'] ||= Utils::RequestId.read_from(env) if Utils::RequestId::REQUEST_ID_HEADERS.include?(key)
89
89
  next if is_server_protocol?(key, value, env["SERVER_PROTOCOL"])
90
90
  next if is_skippable_header?(key)
91
+ next if key == "HTTP_AUTHORIZATION" && !send_default_pii
91
92
 
92
93
  # Rack stores headers as HTTP_WHAT_EVER, we need What-Ever
93
94
  key = key.sub(/^HTTP_/, "")
@@ -6,7 +6,8 @@ module Sentry
6
6
  # @api private
7
7
  module Net
8
8
  module HTTP
9
- OP_NAME = "net.http"
9
+ OP_NAME = "http.client"
10
+ BREADCRUMB_CATEGORY = "net.http"
10
11
 
11
12
  # To explain how the entire thing works, we need to know how the original Net::HTTP#request works
12
13
  # Here's part of its definition. As you can see, it usually calls itself inside a #start block
@@ -53,7 +54,7 @@ module Sentry
53
54
 
54
55
  crumb = Sentry::Breadcrumb.new(
55
56
  level: :info,
56
- category: OP_NAME,
57
+ category: BREADCRUMB_CATEGORY,
57
58
  type: :info,
58
59
  data: {
59
60
  status: res.code.to_i,
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ # @api private
5
+ class Redis
6
+ OP_NAME ||= "db.redis.command"
7
+ LOGGER_NAME ||= :redis_logger
8
+
9
+ def initialize(commands, host, port, db)
10
+ @commands, @host, @port, @db = commands, host, port, db
11
+ end
12
+
13
+ def instrument
14
+ return yield unless Sentry.initialized?
15
+
16
+ record_span do
17
+ yield.tap do
18
+ record_breadcrumb
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :commands, :host, :port, :db
26
+
27
+ def record_span
28
+ return yield unless (transaction = Sentry.get_current_scope.get_transaction) && transaction.sampled
29
+
30
+ sentry_span = transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
31
+
32
+ yield.tap do
33
+ sentry_span.set_description(commands_description)
34
+ sentry_span.set_data(:server, server_description)
35
+ sentry_span.set_timestamp(Sentry.utc_now.to_f)
36
+ end
37
+ end
38
+
39
+ def record_breadcrumb
40
+ return unless Sentry.configuration.breadcrumbs_logger.include?(LOGGER_NAME)
41
+
42
+ Sentry.add_breadcrumb(
43
+ Sentry::Breadcrumb.new(
44
+ level: :info,
45
+ category: OP_NAME,
46
+ type: :info,
47
+ data: {
48
+ commands: parsed_commands,
49
+ server: server_description
50
+ }
51
+ )
52
+ )
53
+ end
54
+
55
+ def commands_description
56
+ parsed_commands.map do |statement|
57
+ statement.values.join(" ").strip
58
+ end.join(", ")
59
+ end
60
+
61
+ def parsed_commands
62
+ commands.map do |statement|
63
+ command, key, *_values = statement
64
+
65
+ { command: command.to_s.upcase, key: key }
66
+ end
67
+ end
68
+
69
+ def server_description
70
+ "#{host}:#{port}/#{db}"
71
+ end
72
+
73
+ module Client
74
+ def logging(commands, &block)
75
+ Sentry::Redis.new(commands, host, port, db).instrument do
76
+ super
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ if defined?(::Redis::Client)
84
+ Sentry.register_patch do
85
+ patch = Sentry::Redis::Client
86
+ Redis::Client.prepend(patch) unless Redis::Client.ancestors.include?(patch)
87
+ end
88
+ end
@@ -164,13 +164,12 @@ module Sentry
164
164
  @name = UNLABELD_NAME
165
165
  end
166
166
 
167
- unless @sampled || @parent_sampled
167
+ if @sampled
168
+ event = hub.current_client.event_from_transaction(self)
169
+ hub.capture_event(event)
170
+ else
168
171
  hub.current_client.transport.record_lost_event(:sample_rate, 'transaction')
169
- return
170
172
  end
171
-
172
- event = hub.current_client.event_from_transaction(self)
173
- hub.capture_event(event)
174
173
  end
175
174
 
176
175
  protected
@@ -3,8 +3,7 @@
3
3
  module Sentry
4
4
  class Transport
5
5
  class Configuration
6
- attr_accessor :timeout, :open_timeout, :proxy, :ssl, :ssl_ca_file, :ssl_verification, :http_adapter, :faraday_builder,
7
- :encoding
6
+ attr_accessor :timeout, :open_timeout, :proxy, :ssl, :ssl_ca_file, :ssl_verification, :encoding
8
7
  attr_reader :transport_class
9
8
 
10
9
  def initialize
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'faraday'
4
- require 'zlib'
3
+ require "net/http"
4
+ require "zlib"
5
5
 
6
6
  module Sentry
7
7
  class HTTPTransport < Transport
@@ -12,14 +12,13 @@ module Sentry
12
12
  DEFAULT_DELAY = 60
13
13
  RETRY_AFTER_HEADER = "retry-after"
14
14
  RATE_LIMIT_HEADER = "x-sentry-rate-limits"
15
-
16
- attr_reader :conn, :adapter
15
+ USER_AGENT = "sentry-ruby/#{Sentry::VERSION}"
17
16
 
18
17
  def initialize(*args)
19
18
  super
20
- @adapter = @transport_configuration.http_adapter || Faraday.default_adapter
21
- @conn = set_conn
22
19
  @endpoint = @dsn.envelope_endpoint
20
+
21
+ log_debug("Sentry HTTP Transport will connect to #{@dsn.server}")
23
22
  end
24
23
 
25
24
  def send_data(data)
@@ -30,29 +29,37 @@ module Sentry
30
29
  encoding = GZIP_ENCODING
31
30
  end
32
31
 
33
- response = conn.post @endpoint do |req|
34
- req.headers['Content-Type'] = CONTENT_TYPE
35
- req.headers['Content-Encoding'] = encoding
36
- req.headers['X-Sentry-Auth'] = generate_auth_header
37
- req.body = data
32
+ headers = {
33
+ 'Content-Type' => CONTENT_TYPE,
34
+ 'Content-Encoding' => encoding,
35
+ 'X-Sentry-Auth' => generate_auth_header,
36
+ 'User-Agent' => USER_AGENT
37
+ }
38
+
39
+ response = conn.start do |http|
40
+ request = ::Net::HTTP::Post.new(@endpoint, headers)
41
+ request.body = data
42
+ http.request(request)
38
43
  end
39
44
 
40
- if has_rate_limited_header?(response.headers)
41
- handle_rate_limited_response(response.headers)
42
- end
43
- rescue Faraday::Error => e
44
- error_info = e.message
45
+ if response.code.match?(/\A2\d{2}/)
46
+ if has_rate_limited_header?(response)
47
+ handle_rate_limited_response(response)
48
+ end
49
+ else
50
+ error_info = "the server responded with status #{response.code}"
45
51
 
46
- if e.response
47
- if e.response[:status] == 429
48
- handle_rate_limited_response(e.response[:headers])
52
+ if response.code == "429"
53
+ handle_rate_limited_response(response)
49
54
  else
50
- error_info += "\nbody: #{e.response[:body]}"
51
- error_info += " Error in headers is: #{e.response[:headers]['x-sentry-error']}" if e.response[:headers]['x-sentry-error']
55
+ error_info += "\nbody: #{response.body}"
56
+ error_info += " Error in headers is: #{response['x-sentry-error']}" if response['x-sentry-error']
52
57
  end
53
- end
54
58
 
55
- raise Sentry::ExternalError, error_info
59
+ raise Sentry::ExternalError, error_info
60
+ end
61
+ rescue SocketError => e
62
+ raise Sentry::ExternalError.new(e.message)
56
63
  end
57
64
 
58
65
  private
@@ -119,32 +126,36 @@ module Sentry
119
126
  @transport_configuration.encoding == GZIP_ENCODING && data.bytesize >= GZIP_THRESHOLD
120
127
  end
121
128
 
122
- def set_conn
123
- server = @dsn.server
129
+ def conn
130
+ server = URI(@dsn.server)
124
131
 
125
- log_debug("Sentry HTTP Transport connecting to #{server}")
132
+ connection =
133
+ if proxy = @transport_configuration.proxy
134
+ ::Net::HTTP.new(server.hostname, server.port, proxy[:uri].hostname, proxy[:uri].port, proxy[:user], proxy[:password])
135
+ else
136
+ ::Net::HTTP.new(server.hostname, server.port, nil)
137
+ end
126
138
 
127
- Faraday.new(server, :ssl => ssl_configuration, :proxy => @transport_configuration.proxy) do |builder|
128
- @transport_configuration.faraday_builder&.call(builder)
129
- builder.response :raise_error
130
- builder.options.merge! faraday_opts
131
- builder.headers[:user_agent] = "sentry-ruby/#{Sentry::VERSION}"
132
- builder.adapter(*adapter)
133
- end
134
- end
139
+ connection.use_ssl = server.scheme == "https"
140
+ connection.read_timeout = @transport_configuration.timeout
141
+ connection.write_timeout = @transport_configuration.timeout if connection.respond_to?(:write_timeout)
142
+ connection.open_timeout = @transport_configuration.open_timeout
135
143
 
136
- # TODO: deprecate and replace where possible w/Faraday Builder
137
- def faraday_opts
138
- [:timeout, :open_timeout].each_with_object({}) do |opt, memo|
139
- memo[opt] = @transport_configuration.public_send(opt) if @transport_configuration.public_send(opt)
144
+ ssl_configuration.each do |key, value|
145
+ connection.send("#{key}=", value)
140
146
  end
147
+
148
+ connection
141
149
  end
142
150
 
143
151
  def ssl_configuration
144
- {
152
+ configuration = {
145
153
  verify: @transport_configuration.ssl_verification,
146
154
  ca_file: @transport_configuration.ssl_ca_file
147
155
  }.merge(@transport_configuration.ssl || {})
156
+
157
+ configuration[:verify_mode] = configuration.delete(:verify) ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
158
+ configuration
148
159
  end
149
160
  end
150
161
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentry
4
- VERSION = "4.9.2"
4
+ VERSION = "5.1.0"
5
5
  end
data/lib/sentry-ruby.rb CHANGED
@@ -111,9 +111,17 @@ module Sentry
111
111
 
112
112
  # @!method configuration
113
113
  # @!macro configuration
114
+ def configuration
115
+ return unless initialized?
116
+ get_current_client.configuration
117
+ end
118
+
114
119
  # @!method send_event
115
120
  # @!macro send_event
116
- def_delegators :get_current_client, :configuration, :send_event
121
+ def send_event(*args)
122
+ return unless initialized?
123
+ get_current_client.send_event(*args)
124
+ end
117
125
 
118
126
  # @!macro [new] set_extras
119
127
  # Updates the scope's extras attribute by merging with the old value.
@@ -135,13 +143,31 @@ module Sentry
135
143
 
136
144
  # @!method set_tags
137
145
  # @!macro set_tags
146
+ def set_tags(*args)
147
+ return unless initialized?
148
+ get_current_scope.set_tags(*args)
149
+ end
150
+
138
151
  # @!method set_extras
139
152
  # @!macro set_extras
153
+ def set_extras(*args)
154
+ return unless initialized?
155
+ get_current_scope.set_extras(*args)
156
+ end
157
+
140
158
  # @!method set_user
141
159
  # @!macro set_user
160
+ def set_user(*args)
161
+ return unless initialized?
162
+ get_current_scope.set_user(*args)
163
+ end
164
+
142
165
  # @!method set_context
143
166
  # @!macro set_context
144
- def_delegators :get_current_scope, :set_tags, :set_extras, :set_user, :set_context
167
+ def set_context(*args)
168
+ return unless initialized?
169
+ get_current_scope.set_context(*args)
170
+ end
145
171
 
146
172
  ##### Main APIs #####
147
173
 
@@ -201,7 +227,8 @@ module Sentry
201
227
  #
202
228
  # @return [Breadcrumb, nil]
203
229
  def add_breadcrumb(breadcrumb, **options)
204
- get_current_hub&.add_breadcrumb(breadcrumb, **options)
230
+ return unless initialized?
231
+ get_current_hub.add_breadcrumb(breadcrumb, **options)
205
232
  end
206
233
 
207
234
  # Returns the current active hub.
@@ -221,14 +248,16 @@ module Sentry
221
248
  # Returns the current active client.
222
249
  # @return [Client, nil]
223
250
  def get_current_client
224
- get_current_hub&.current_client
251
+ return unless initialized?
252
+ get_current_hub.current_client
225
253
  end
226
254
 
227
255
  # Returns the current active scope.
228
256
  #
229
257
  # @return [Scope, nil]
230
258
  def get_current_scope
231
- get_current_hub&.current_scope
259
+ return unless initialized?
260
+ get_current_hub.current_scope
232
261
  end
233
262
 
234
263
  # Clones the main thread's active hub and stores it to the current thread.
@@ -250,7 +279,8 @@ module Sentry
250
279
  # @yieldparam scope [Scope]
251
280
  # @return [void]
252
281
  def configure_scope(&block)
253
- get_current_hub&.configure_scope(&block)
282
+ return unless initialized?
283
+ get_current_hub.configure_scope(&block)
254
284
  end
255
285
 
256
286
  # Takes a block and yields a temporary scope.
@@ -274,7 +304,8 @@ module Sentry
274
304
  # @yieldparam scope [Scope]
275
305
  # @return [void]
276
306
  def with_scope(&block)
277
- get_current_hub&.with_scope(&block)
307
+ return unless initialized?
308
+ get_current_hub.with_scope(&block)
278
309
  end
279
310
 
280
311
  # Takes an exception and reports it to Sentry via the currently active hub.
@@ -282,7 +313,8 @@ module Sentry
282
313
  # @yieldparam scope [Scope]
283
314
  # @return [Event, nil]
284
315
  def capture_exception(exception, **options, &block)
285
- get_current_hub&.capture_exception(exception, **options, &block)
316
+ return unless initialized?
317
+ get_current_hub.capture_exception(exception, **options, &block)
286
318
  end
287
319
 
288
320
  # Takes a message string and reports it to Sentry via the currently active hub.
@@ -290,28 +322,32 @@ module Sentry
290
322
  # @yieldparam scope [Scope]
291
323
  # @return [Event, nil]
292
324
  def capture_message(message, **options, &block)
293
- get_current_hub&.capture_message(message, **options, &block)
325
+ return unless initialized?
326
+ get_current_hub.capture_message(message, **options, &block)
294
327
  end
295
328
 
296
329
  # Takes an instance of Sentry::Event and dispatches it to the currently active hub.
297
330
  #
298
331
  # @return [Event, nil]
299
332
  def capture_event(event)
300
- get_current_hub&.capture_event(event)
333
+ return unless initialized?
334
+ get_current_hub.capture_event(event)
301
335
  end
302
336
 
303
337
  # Takes or initializes a new Sentry::Transaction and makes a sampling decision for it.
304
338
  #
305
339
  # @return [Transaction, nil]
306
340
  def start_transaction(**options)
307
- get_current_hub&.start_transaction(**options)
341
+ return unless initialized?
342
+ get_current_hub.start_transaction(**options)
308
343
  end
309
344
 
310
345
  # Returns the id of the lastly reported Sentry::Event.
311
346
  #
312
347
  # @return [String, nil]
313
348
  def last_event_id
314
- get_current_hub&.last_event_id
349
+ return unless initialized?
350
+ get_current_hub.last_event_id
315
351
  end
316
352
 
317
353
 
@@ -344,3 +380,4 @@ end
344
380
 
345
381
  # patches
346
382
  require "sentry/net/http"
383
+ 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
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sentry-ruby-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.9.2
4
+ version: 5.1.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: 2022-01-18 00:00:00.000000000 Z
11
+ date: 2022-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: faraday
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: concurrent-ruby
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -87,6 +73,7 @@ files:
87
73
  - lib/sentry/rack.rb
88
74
  - lib/sentry/rack/capture_exceptions.rb
89
75
  - lib/sentry/rake.rb
76
+ - lib/sentry/redis.rb
90
77
  - lib/sentry/release_detector.rb
91
78
  - lib/sentry/scope.rb
92
79
  - lib/sentry/span.rb