sentry-ruby-core 5.18.2 → 5.19.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: afb4ea80437f41e79f4587ee2fa26d15840774a9b6381ade3d601b4669fad270
4
- data.tar.gz: 2ba353d4fdbe545c8e76fbd2c3b0169f481965e8e55cc74ad3e4cd613b6c4f76
3
+ metadata.gz: b47e81567b685cb3ad64e889f638f7dd9b97ee8c7cf3e0eee5907c053cf784dc
4
+ data.tar.gz: 9480a3870fce66342cffae3f818f220658d8f8368c46d481a27a9bbba9f3c8a1
5
5
  SHA512:
6
- metadata.gz: 87d277ecb542c59d04b37c8ba28a20236cefde3e096ea01ad2d2ffa3127a3afb07737da494e8707650d7cd608f113754e51d33ade8404111b2bfb9cd03964f38
7
- data.tar.gz: aebeeb641244f112b0957f409d0055379f168413354e25f19118744e79352b12159b693945c1bfc506e8d14ad076b115c9e7037be6d7bbe08114b3f6b7370df5
6
+ metadata.gz: 7afc772277ecf7be43cc029f4cf988585f469f08d1fcfab696bad471a1ddb8269c18f8c946a3af94a8bf4775f93ef9851c57940b05f8c09cb90de812e15f9f6d
7
+ data.tar.gz: 1f1236a73ed900dc9d38a5448c154dcf4a66ab55eb490528e214f1b3f393a99eccbaa1d303d9c8a3064060b0447c21d6d59f5fdbbcb843203c0e00a4c18adb89
data/Gemfile CHANGED
@@ -24,5 +24,6 @@ gem "benchmark-memory"
24
24
 
25
25
  gem "yard", github: "lsegal/yard"
26
26
  gem "webrick"
27
+ gem "faraday"
27
28
 
28
29
  eval_gemfile File.expand_path("../Gemfile", __dir__)
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ class Attachment
5
+ PathNotFoundError = Class.new(StandardError)
6
+
7
+ attr_reader :bytes, :filename, :path, :content_type
8
+
9
+ def initialize(bytes: nil, filename: nil, content_type: nil, path: nil)
10
+ @bytes = bytes
11
+ @filename = infer_filename(filename, path)
12
+ @path = path
13
+ @content_type = content_type
14
+ end
15
+
16
+ def to_envelope_headers
17
+ { type: 'attachment', filename: filename, content_type: content_type, length: payload.bytesize }
18
+ end
19
+
20
+ def payload
21
+ @payload ||= if bytes
22
+ bytes
23
+ else
24
+ File.binread(path)
25
+ end
26
+ rescue Errno::ENOENT
27
+ raise PathNotFoundError, "Failed to read attachment file, file not found: #{path}"
28
+ end
29
+
30
+ private
31
+
32
+ def infer_filename(filename, path)
33
+ return filename if filename
34
+
35
+ if path
36
+ File.basename(path)
37
+ else
38
+ raise ArgumentError, "filename or path is required"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -656,11 +656,8 @@ module Sentry
656
656
  end
657
657
 
658
658
  def processor_count
659
- if Concurrent.respond_to?(:usable_processor_count)
660
- Concurrent.usable_processor_count
661
- else
662
- Concurrent.processor_count
663
- end
659
+ available_processor_count = Concurrent.available_processor_count if Concurrent.respond_to?(:available_processor_count)
660
+ available_processor_count || Concurrent.processor_count
664
661
  end
665
662
  end
666
663
  end
data/lib/sentry/event.rb CHANGED
@@ -42,6 +42,9 @@ module Sentry
42
42
  # @return [Hash, nil]
43
43
  attr_accessor :dynamic_sampling_context
44
44
 
45
+ # @return [Array<Attachment>]
46
+ attr_accessor :attachments
47
+
45
48
  # @param configuration [Configuration]
46
49
  # @param integration_meta [Hash, nil]
47
50
  # @param message [String, nil]
@@ -57,6 +60,7 @@ module Sentry
57
60
  @extra = {}
58
61
  @contexts = {}
59
62
  @tags = {}
63
+ @attachments = []
60
64
 
61
65
  @fingerprint = []
62
66
  @dynamic_sampling_context = nil
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ module Faraday
5
+ OP_NAME = "http.client"
6
+
7
+ module Connection
8
+ # Since there's no way to preconfigure Faraday connections and add our instrumentation
9
+ # by default, we need to extend the connection constructor and do it there
10
+ #
11
+ # @see https://lostisland.github.io/faraday/#/customization/index?id=configuration
12
+ def initialize(url = nil, options = nil)
13
+ super
14
+
15
+ # Ensure that we attach instrumentation only if the adapter is not net/http
16
+ # because if is is, then the net/http instrumentation will take care of it
17
+ if builder.adapter.name != "Faraday::Adapter::NetHttp"
18
+ # Make sure that it's going to be the first middleware so that it can capture
19
+ # the entire request processing involving other middlewares
20
+ builder.insert(0, ::Faraday::Request::Instrumentation, name: OP_NAME, instrumenter: Instrumenter.new)
21
+ end
22
+ end
23
+ end
24
+
25
+ class Instrumenter
26
+ SPAN_ORIGIN = "auto.http.faraday"
27
+ BREADCRUMB_CATEGORY = "http"
28
+
29
+ include Utils::HttpTracing
30
+
31
+ def instrument(op_name, env, &block)
32
+ return block.call unless Sentry.initialized?
33
+
34
+ Sentry.with_child_span(op: op_name, start_timestamp: Sentry.utc_now.to_f, origin: SPAN_ORIGIN) do |sentry_span|
35
+ request_info = extract_request_info(env)
36
+
37
+ if propagate_trace?(request_info[:url])
38
+ set_propagation_headers(env[:request_headers])
39
+ end
40
+
41
+ res = block.call
42
+ response_status = res.status
43
+
44
+ if record_sentry_breadcrumb?
45
+ record_sentry_breadcrumb(request_info, response_status)
46
+ end
47
+
48
+ if sentry_span
49
+ set_span_info(sentry_span, request_info, response_status)
50
+ end
51
+
52
+ res
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def extract_request_info(env)
59
+ url = env[:url].scheme + "://" + env[:url].host + env[:url].path
60
+ result = { method: env[:method].to_s.upcase, url: url }
61
+
62
+ if Sentry.configuration.send_default_pii
63
+ result[:query] = env[:url].query
64
+ result[:body] = env[:body]
65
+ end
66
+
67
+ result
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ Sentry.register_patch(:faraday) do
74
+ if defined?(::Faraday)
75
+ ::Faraday::Connection.prepend(Sentry::Faraday::Connection)
76
+ end
77
+ end
@@ -2,11 +2,14 @@
2
2
 
3
3
  require "net/http"
4
4
  require "resolv"
5
+ require "sentry/utils/http_tracing"
5
6
 
6
7
  module Sentry
7
8
  # @api private
8
9
  module Net
9
10
  module HTTP
11
+ include Utils::HttpTracing
12
+
10
13
  OP_NAME = "http.client"
11
14
  SPAN_ORIGIN = "auto.http.net_http"
12
15
  BREADCRUMB_CATEGORY = "net.http"
@@ -21,8 +24,7 @@ module Sentry
21
24
  # req['connection'] ||= 'close'
22
25
  # return request(req, body, &block) # <- request will be called for the second time from the first call
23
26
  # }
24
- # end
25
- # # .....
27
+ # end # .....
26
28
  # end
27
29
  # ```
28
30
  #
@@ -34,44 +36,26 @@ module Sentry
34
36
  Sentry.with_child_span(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f, origin: SPAN_ORIGIN) do |sentry_span|
35
37
  request_info = extract_request_info(req)
36
38
 
37
- if propagate_trace?(request_info[:url], Sentry.configuration)
39
+ if propagate_trace?(request_info[:url])
38
40
  set_propagation_headers(req)
39
41
  end
40
42
 
41
- super.tap do |res|
42
- record_sentry_breadcrumb(request_info, res)
43
+ res = super
44
+ response_status = res.code.to_i
43
45
 
44
- if sentry_span
45
- sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
46
- sentry_span.set_data(Span::DataConventions::URL, request_info[:url])
47
- sentry_span.set_data(Span::DataConventions::HTTP_METHOD, request_info[:method])
48
- sentry_span.set_data(Span::DataConventions::HTTP_QUERY, request_info[:query]) if request_info[:query]
49
- sentry_span.set_data(Span::DataConventions::HTTP_STATUS_CODE, res.code.to_i)
50
- end
46
+ if record_sentry_breadcrumb?
47
+ record_sentry_breadcrumb(request_info, response_status)
51
48
  end
52
- end
53
- end
54
49
 
55
- private
50
+ if sentry_span
51
+ set_span_info(sentry_span, request_info, response_status)
52
+ end
56
53
 
57
- def set_propagation_headers(req)
58
- Sentry.get_trace_propagation_headers&.each { |k, v| req[k] = v }
54
+ res
55
+ end
59
56
  end
60
57
 
61
- def record_sentry_breadcrumb(request_info, res)
62
- return unless Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
63
-
64
- crumb = Sentry::Breadcrumb.new(
65
- level: :info,
66
- category: BREADCRUMB_CATEGORY,
67
- type: :info,
68
- data: {
69
- status: res.code.to_i,
70
- **request_info
71
- }
72
- )
73
- Sentry.add_breadcrumb(crumb)
74
- end
58
+ private
75
59
 
76
60
  def from_sentry_sdk?
77
61
  dsn = Sentry.configuration.dsn
@@ -94,12 +78,6 @@ module Sentry
94
78
 
95
79
  result
96
80
  end
97
-
98
- def propagate_trace?(url, configuration)
99
- url &&
100
- configuration.propagate_traces &&
101
- configuration.trace_propagation_targets.any? { |target| url.match?(target) }
102
- end
103
81
  end
104
82
  end
105
83
  end
data/lib/sentry/scope.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "sentry/breadcrumb_buffer"
4
4
  require "sentry/propagation_context"
5
+ require "sentry/attachment"
5
6
  require "etc"
6
7
 
7
8
  module Sentry
@@ -22,6 +23,7 @@ module Sentry
22
23
  :rack_env,
23
24
  :span,
24
25
  :session,
26
+ :attachments,
25
27
  :propagation_context
26
28
  ]
27
29
 
@@ -55,6 +57,7 @@ module Sentry
55
57
  event.level = level
56
58
  event.breadcrumbs = breadcrumbs
57
59
  event.rack_env = rack_env if rack_env
60
+ event.attachments = attachments
58
61
  end
59
62
 
60
63
  if span
@@ -102,6 +105,7 @@ module Sentry
102
105
  copy.span = span.deep_dup
103
106
  copy.session = session.deep_dup
104
107
  copy.propagation_context = propagation_context.deep_dup
108
+ copy.attachments = attachments.dup
105
109
  copy
106
110
  end
107
111
 
@@ -119,6 +123,7 @@ module Sentry
119
123
  self.fingerprint = scope.fingerprint
120
124
  self.span = scope.span
121
125
  self.propagation_context = scope.propagation_context
126
+ self.attachments = scope.attachments
122
127
  end
123
128
 
124
129
  # Updates the scope's data from the given options.
@@ -128,6 +133,7 @@ module Sentry
128
133
  # @param user [Hash]
129
134
  # @param level [String, Symbol]
130
135
  # @param fingerprint [Array]
136
+ # @param attachments [Array<Attachment>]
131
137
  # @return [Array]
132
138
  def update_from_options(
133
139
  contexts: nil,
@@ -136,6 +142,7 @@ module Sentry
136
142
  user: nil,
137
143
  level: nil,
138
144
  fingerprint: nil,
145
+ attachments: nil,
139
146
  **options
140
147
  )
141
148
  self.contexts.merge!(contexts) if contexts
@@ -283,6 +290,12 @@ module Sentry
283
290
  @propagation_context = PropagationContext.new(self, env)
284
291
  end
285
292
 
293
+ # Add a new attachment to the scope.
294
+ def add_attachment(**opts)
295
+ attachments << (attachment = Attachment.new(**opts))
296
+ attachment
297
+ end
298
+
286
299
  protected
287
300
 
288
301
  # for duplicating scopes internally
@@ -303,6 +316,7 @@ module Sentry
303
316
  @rack_env = {}
304
317
  @span = nil
305
318
  @session = nil
319
+ @attachments = []
306
320
  generate_propagation_context
307
321
  set_new_breadcrumb_buffer
308
322
  end
data/lib/sentry/span.rb CHANGED
@@ -192,7 +192,8 @@ module Sentry
192
192
  description: @description,
193
193
  op: @op,
194
194
  status: @status,
195
- origin: @origin
195
+ origin: @origin,
196
+ data: @data
196
197
  }
197
198
  end
198
199
 
@@ -145,6 +145,12 @@ module Sentry
145
145
  )
146
146
  end
147
147
 
148
+ if event.is_a?(Event) && event.attachments.any?
149
+ event.attachments.each do |attachment|
150
+ envelope.add_item(attachment.to_envelope_headers, attachment.payload)
151
+ end
152
+ end
153
+
148
154
  client_report_headers, client_report_payload = fetch_pending_client_report
149
155
  envelope.add_item(client_report_headers, client_report_payload) if client_report_headers
150
156
 
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sentry
4
+ module Utils
5
+ module HttpTracing
6
+ def set_span_info(sentry_span, request_info, response_status)
7
+ sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
8
+ sentry_span.set_data(Span::DataConventions::URL, request_info[:url])
9
+ sentry_span.set_data(Span::DataConventions::HTTP_METHOD, request_info[:method])
10
+ sentry_span.set_data(Span::DataConventions::HTTP_QUERY, request_info[:query]) if request_info[:query]
11
+ sentry_span.set_data(Span::DataConventions::HTTP_STATUS_CODE, response_status)
12
+ end
13
+
14
+ def set_propagation_headers(req)
15
+ Sentry.get_trace_propagation_headers&.each { |k, v| req[k] = v }
16
+ end
17
+
18
+ def record_sentry_breadcrumb(request_info, response_status)
19
+ crumb = Sentry::Breadcrumb.new(
20
+ level: :info,
21
+ category: self.class::BREADCRUMB_CATEGORY,
22
+ type: :info,
23
+ data: { status: response_status, **request_info }
24
+ )
25
+
26
+ Sentry.add_breadcrumb(crumb)
27
+ end
28
+
29
+ def record_sentry_breadcrumb?
30
+ Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
31
+ end
32
+
33
+ def propagate_trace?(url)
34
+ url &&
35
+ Sentry.initialized? &&
36
+ Sentry.configuration.propagate_traces &&
37
+ Sentry.configuration.trace_propagation_targets.any? { |target| url.match?(target) }
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentry
4
- VERSION = "5.18.2"
4
+ VERSION = "5.19.0"
5
5
  end
data/lib/sentry-ruby.rb CHANGED
@@ -211,6 +211,13 @@ module Sentry
211
211
  get_current_scope.set_context(*args)
212
212
  end
213
213
 
214
+ # @!method add_attachment
215
+ # @!macro add_attachment
216
+ def add_attachment(**opts)
217
+ return unless initialized?
218
+ get_current_scope.add_attachment(**opts)
219
+ end
220
+
214
221
  ##### Main APIs #####
215
222
 
216
223
  # Initializes the SDK with given configuration.
@@ -601,3 +608,4 @@ require "sentry/net/http"
601
608
  require "sentry/redis"
602
609
  require "sentry/puma"
603
610
  require "sentry/graphql"
611
+ require "sentry/faraday"
data/sentry-ruby.gemspec CHANGED
@@ -26,6 +26,6 @@ Gem::Specification.new do |spec|
26
26
 
27
27
  spec.require_paths = ["lib"]
28
28
 
29
- spec.add_dependency "concurrent-ruby", '~> 1.0', '>= 1.0.2'
29
+ spec.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2"
30
30
  spec.add_dependency "bigdecimal"
31
31
  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: 5.18.2
4
+ version: 5.19.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: 2024-07-23 00:00:00.000000000 Z
11
+ date: 2024-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sentry-ruby
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 5.18.2
19
+ version: 5.19.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 5.18.2
26
+ version: 5.19.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: concurrent-ruby
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,6 +58,7 @@ files:
58
58
  - bin/console
59
59
  - bin/setup
60
60
  - lib/sentry-ruby.rb
61
+ - lib/sentry/attachment.rb
61
62
  - lib/sentry/background_worker.rb
62
63
  - lib/sentry/backpressure_monitor.rb
63
64
  - lib/sentry/backtrace.rb
@@ -79,6 +80,7 @@ files:
79
80
  - lib/sentry/error_event.rb
80
81
  - lib/sentry/event.rb
81
82
  - lib/sentry/exceptions.rb
83
+ - lib/sentry/faraday.rb
82
84
  - lib/sentry/graphql.rb
83
85
  - lib/sentry/hub.rb
84
86
  - lib/sentry/integrable.rb
@@ -128,6 +130,7 @@ files:
128
130
  - lib/sentry/utils/custom_inspection.rb
129
131
  - lib/sentry/utils/encoding_helper.rb
130
132
  - lib/sentry/utils/exception_cause_chain.rb
133
+ - lib/sentry/utils/http_tracing.rb
131
134
  - lib/sentry/utils/logging_helper.rb
132
135
  - lib/sentry/utils/real_ip.rb
133
136
  - lib/sentry/utils/request_id.rb