sentry-ruby-core 5.17.2 → 5.17.3

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: be9c1bd29350d0e6a59ee415c3ab1b2509172c9e6e566b3c2bdcd013c80fc8cf
4
- data.tar.gz: 39b5b3fe8b54be43ecfd06cc39981e670a9c07d86d303a412aa4d83577155513
3
+ metadata.gz: fe82a2b6001d48448ad45cfdfcf6eca4c99708b33ca289afc1777dac54dcd851
4
+ data.tar.gz: db84b44742d0e847b6fd66dac5a3338e63d4497723979b7c71fbbea46eb50480
5
5
  SHA512:
6
- metadata.gz: 7efacb821bec171862390a6cda4353a94a32cdb064b63eb4b6b665a52798fa7338dd41df5648e6e32a5f45311455f13eb69cf8a852d197c44863aa16adc6dce1
7
- data.tar.gz: d75b0125443e8cff217fc1c4a6c9ff5dc1ff7ee51542e19ab3d3768e2f716233196afdcc72883b9b451d42817bd7a974c73095c27b48abfaffa089ae9a78d066
6
+ metadata.gz: 0b5cd84206fa239965fdfddc7a9570c2ca8c490f61055ec7c4b919d5e9ab299accbb6b8588a939101e4c3605a043f2e33392baa14f11a8bf1868ed78bf0f8fb7
7
+ data.tar.gz: 1348bd6636f8283af3d85934ffe414606072758939cc0027c70730f8711f933ab72d9ee23d49cd921ca3562dcd4a034f93255fe5f3eb257a0e4288815be840e5
data/lib/sentry/client.rb CHANGED
@@ -49,16 +49,17 @@ module Sentry
49
49
  return unless configuration.sending_allowed?
50
50
 
51
51
  if event.is_a?(ErrorEvent) && !configuration.sample_allowed?
52
- transport.record_lost_event(:sample_rate, 'event')
52
+ transport.record_lost_event(:sample_rate, 'error')
53
53
  return
54
54
  end
55
55
 
56
56
  event_type = event.is_a?(Event) ? event.type : event["type"]
57
+ data_category = Envelope::Item.data_category(event_type)
57
58
  event = scope.apply_to_event(event, hint)
58
59
 
59
60
  if event.nil?
60
61
  log_debug("Discarded event because one of the event processors returned nil")
61
- transport.record_lost_event(:event_processor, event_type)
62
+ transport.record_lost_event(:event_processor, data_category)
62
63
  return
63
64
  end
64
65
 
@@ -66,7 +67,7 @@ module Sentry
66
67
  dispatch_async_event(async_block, event, hint)
67
68
  elsif configuration.background_worker_threads != 0 && hint.fetch(:background, true)
68
69
  queued = dispatch_background_event(event, hint)
69
- transport.record_lost_event(:queue_overflow, event_type) unless queued
70
+ transport.record_lost_event(:queue_overflow, data_category) unless queued
70
71
  else
71
72
  send_event(event, hint)
72
73
  end
@@ -77,6 +78,20 @@ module Sentry
77
78
  nil
78
79
  end
79
80
 
81
+ # Capture an envelope directly.
82
+ # @param envelope [Envelope] the envelope to be captured.
83
+ # @return [void]
84
+ def capture_envelope(envelope)
85
+ Sentry.background_worker.perform { send_envelope(envelope) }
86
+ end
87
+
88
+ # Flush pending events to Sentry.
89
+ # @return [void]
90
+ def flush
91
+ transport.flush if configuration.sending_to_dsn_allowed?
92
+ spotlight_transport.flush if spotlight_transport
93
+ end
94
+
80
95
  # Initializes an Event object with the given exception. Returns `nil` if the exception's class is excluded from reporting.
81
96
  # @param exception [Exception] the exception to be reported.
82
97
  # @param hint [Hash] the hint data that'll be passed to `before_send` callback and the scope's event processors.
@@ -152,13 +167,14 @@ module Sentry
152
167
  # @!macro send_event
153
168
  def send_event(event, hint = nil)
154
169
  event_type = event.is_a?(Event) ? event.type : event["type"]
170
+ data_category = Envelope::Item.data_category(event_type)
155
171
 
156
172
  if event_type != TransactionEvent::TYPE && configuration.before_send
157
173
  event = configuration.before_send.call(event, hint)
158
174
 
159
175
  if event.nil?
160
176
  log_debug("Discarded event because before_send returned nil")
161
- transport.record_lost_event(:before_send, 'event')
177
+ transport.record_lost_event(:before_send, data_category)
162
178
  return
163
179
  end
164
180
  end
@@ -168,7 +184,7 @@ module Sentry
168
184
 
169
185
  if event.nil?
170
186
  log_debug("Discarded event because before_send_transaction returned nil")
171
- transport.record_lost_event(:before_send, 'transaction')
187
+ transport.record_lost_event(:before_send, data_category)
172
188
  return
173
189
  end
174
190
  end
@@ -179,7 +195,23 @@ module Sentry
179
195
  event
180
196
  rescue => e
181
197
  log_error("Event sending failed", e, debug: configuration.debug)
182
- transport.record_lost_event(:network_error, event_type)
198
+ transport.record_lost_event(:network_error, data_category)
199
+ raise
200
+ end
201
+
202
+ # Send an envelope directly to Sentry.
203
+ # @param envelope [Envelope] the envelope to be sent.
204
+ # @return [void]
205
+ def send_envelope(envelope)
206
+ transport.send_envelope(envelope) if configuration.sending_to_dsn_allowed?
207
+ spotlight_transport.send_envelope(envelope) if spotlight_transport
208
+ rescue => e
209
+ log_error("Envelope sending failed", e, debug: configuration.debug)
210
+
211
+ envelope.items.map(&:data_category).each do |data_category|
212
+ transport.record_lost_event(:network_error, data_category)
213
+ end
214
+
183
215
  raise
184
216
  end
185
217
 
@@ -18,6 +18,23 @@ module Sentry
18
18
  @headers[:type] || 'event'
19
19
  end
20
20
 
21
+ # rate limits and client reports use the data_category rather than envelope item type
22
+ def self.data_category(type)
23
+ case type
24
+ when 'session', 'attachment', 'transaction', 'profile' then type
25
+ when 'sessions' then 'session'
26
+ when 'check_in' then 'monitor'
27
+ when 'statsd', 'metric_meta' then 'metric_bucket'
28
+ when 'event' then 'error'
29
+ when 'client_report' then 'internal'
30
+ else 'default'
31
+ end
32
+ end
33
+
34
+ def data_category
35
+ self.class.data_category(type)
36
+ end
37
+
21
38
  def to_s
22
39
  [JSON.generate(@headers), @payload.is_a?(String) ? @payload : JSON.generate(@payload)].join("\n")
23
40
  end
@@ -12,8 +12,18 @@ module Sentry
12
12
  # when we record code locations
13
13
  DEFAULT_STACKLEVEL = 4
14
14
 
15
- KEY_SANITIZATION_REGEX = /[^a-zA-Z0-9_\/.-]+/
16
- VALUE_SANITIZATION_REGEX = /[^[[:word:]][[:digit:]][[:space:]]_:\/@\.{}\[\]$-]+/
15
+ KEY_SANITIZATION_REGEX = /[^a-zA-Z0-9_\-.]+/
16
+ UNIT_SANITIZATION_REGEX = /[^a-zA-Z0-9_]+/
17
+ TAG_KEY_SANITIZATION_REGEX = /[^a-zA-Z0-9_\-.\/]+/
18
+
19
+ TAG_VALUE_SANITIZATION_MAP = {
20
+ "\n" => "\\n",
21
+ "\r" => "\\r",
22
+ "\t" => "\\t",
23
+ "\\" => "\\\\",
24
+ "|" => "\\u{7c}",
25
+ "," => "\\u{2c}"
26
+ }
17
27
 
18
28
  METRIC_TYPES = {
19
29
  c: CounterMetric,
@@ -23,7 +33,7 @@ module Sentry
23
33
  }
24
34
 
25
35
  # exposed only for testing
26
- attr_reader :thread, :buckets, :flush_shift, :code_locations
36
+ attr_reader :client, :thread, :buckets, :flush_shift, :code_locations
27
37
 
28
38
  def initialize(configuration, client)
29
39
  @client = client
@@ -107,9 +117,7 @@ module Sentry
107
117
  end
108
118
  end
109
119
 
110
- Sentry.background_worker.perform do
111
- @client.transport.send_envelope(envelope)
112
- end
120
+ @client.capture_envelope(envelope)
113
121
  end
114
122
 
115
123
  def kill
@@ -182,9 +190,9 @@ module Sentry
182
190
  timestamp_buckets.map do |metric_key, metric|
183
191
  type, key, unit, tags = metric_key
184
192
  values = metric.serialize.join(':')
185
- sanitized_tags = tags.map { |k, v| "#{sanitize_key(k)}:#{sanitize_value(v)}" }.join(',')
193
+ sanitized_tags = tags.map { |k, v| "#{sanitize_tag_key(k)}:#{sanitize_tag_value(v)}" }.join(',')
186
194
 
187
- "#{sanitize_key(key)}@#{unit}:#{values}|#{type}|\##{sanitized_tags}|T#{timestamp}"
195
+ "#{sanitize_key(key)}@#{sanitize_unit(unit)}:#{values}|#{type}|\##{sanitized_tags}|T#{timestamp}"
188
196
  end
189
197
  end.flatten.join("\n")
190
198
  end
@@ -192,7 +200,7 @@ module Sentry
192
200
  def serialize_locations(timestamp, locations)
193
201
  mapping = locations.map do |meta_key, location|
194
202
  type, key, unit = meta_key
195
- mri = "#{type}:#{sanitize_key(key)}@#{unit}"
203
+ mri = "#{type}:#{sanitize_key(key)}@#{sanitize_unit(unit)}"
196
204
 
197
205
  # note this needs to be an array but it really doesn't serve a purpose right now
198
206
  [mri, [location.merge(type: 'location')]]
@@ -205,8 +213,16 @@ module Sentry
205
213
  key.gsub(KEY_SANITIZATION_REGEX, '_')
206
214
  end
207
215
 
208
- def sanitize_value(value)
209
- value.gsub(VALUE_SANITIZATION_REGEX, '')
216
+ def sanitize_unit(unit)
217
+ unit.gsub(UNIT_SANITIZATION_REGEX, '')
218
+ end
219
+
220
+ def sanitize_tag_key(key)
221
+ key.gsub(TAG_KEY_SANITIZATION_REGEX, '')
222
+ end
223
+
224
+ def sanitize_tag_value(value)
225
+ value.chars.map { |c| TAG_VALUE_SANITIZATION_MAP[c] || c }.join
210
226
  end
211
227
 
212
228
  def get_transaction_name
@@ -20,12 +20,8 @@ module Sentry
20
20
 
21
21
  def flush
22
22
  return if @pending_aggregates.empty?
23
- envelope = pending_envelope
24
-
25
- Sentry.background_worker.perform do
26
- @client.transport.send_envelope(envelope)
27
- end
28
23
 
24
+ @client.capture_envelope(pending_envelope)
29
25
  @pending_aggregates = {}
30
26
  end
31
27
 
@@ -88,18 +88,9 @@ module Sentry
88
88
  [data, serialized_items]
89
89
  end
90
90
 
91
- def is_rate_limited?(item_type)
91
+ def is_rate_limited?(data_category)
92
92
  # check category-specific limit
93
- category_delay =
94
- case item_type
95
- when "transaction"
96
- @rate_limits["transaction"]
97
- when "sessions"
98
- @rate_limits["session"]
99
- else
100
- @rate_limits["error"]
101
- end
102
-
93
+ category_delay = @rate_limits[data_category]
103
94
  # check universal limit if not category limit
104
95
  universal_delay = @rate_limits[nil]
105
96
 
@@ -160,11 +151,11 @@ module Sentry
160
151
  envelope
161
152
  end
162
153
 
163
- def record_lost_event(reason, item_type)
154
+ def record_lost_event(reason, data_category)
164
155
  return unless @send_client_reports
165
156
  return unless CLIENT_REPORT_REASONS.include?(reason)
166
157
 
167
- @discarded_events[[reason, item_type]] += 1
158
+ @discarded_events[[reason, data_category]] += 1
168
159
  end
169
160
 
170
161
  def flush
@@ -184,11 +175,7 @@ module Sentry
184
175
  return nil if @discarded_events.empty?
185
176
 
186
177
  discarded_events_hash = @discarded_events.map do |key, val|
187
- reason, type = key
188
-
189
- # 'event' has to be mapped to 'error'
190
- category = type == 'event' ? 'error' : type
191
-
178
+ reason, category = key
192
179
  { reason: reason, category: category, quantity: val }
193
180
  end
194
181
 
@@ -206,9 +193,9 @@ module Sentry
206
193
 
207
194
  def reject_rate_limited_items(envelope)
208
195
  envelope.items.reject! do |item|
209
- if is_rate_limited?(item.type)
196
+ if is_rate_limited?(item.data_category)
210
197
  log_debug("[Transport] Envelope item [#{item.type}] not sent: rate limiting")
211
- record_lost_event(:ratelimit_backoff, item.type)
198
+ record_lost_event(:ratelimit_backoff, item.data_category)
212
199
 
213
200
  true
214
201
  else
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sentry
4
- VERSION = "5.17.2"
4
+ VERSION = "5.17.3"
5
5
  end
data/lib/sentry-ruby.rb CHANGED
@@ -257,7 +257,7 @@ module Sentry
257
257
  end
258
258
 
259
259
  if client = get_current_client
260
- client.transport.flush
260
+ client.flush
261
261
 
262
262
  if client.configuration.include_local_variables
263
263
  exception_locals_tp.disable
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.17.2
4
+ version: 5.17.3
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-04-03 00:00:00.000000000 Z
11
+ date: 2024-04-11 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.17.2
19
+ version: 5.17.3
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.17.2
26
+ version: 5.17.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: concurrent-ruby
29
29
  requirement: !ruby/object:Gem::Requirement